Merge pull request #10 from gunyarakun/fix-invalid-return
[cocotron.git] / Onyx2D / O2TTFDecoder.m
bloba8b832a1047c724ec395768ce661131fc9136905
1 #import <Onyx2D/O2TTFDecoder.h>
2 #import <Onyx2D/O2DataProvider.h>
3 #import <Onyx2D/O2Font.h>
4 #import <Onyx2D/O2MutablePath.h>
5 #import <Foundation/NSMapTable.h>
7 @implementation O2TTFDecoder
9 typedef uint32_t Fixed32;
10 typedef uint16_t FWord16;
11 typedef int64_t  longDateTime64;
13 O2TTFDecoderRef O2TTFDecoderCreate(O2DataProviderRef dataProvider) {
14    O2TTFDecoderRef self=NSAllocateObject([O2TTFDecoder class],0,NULL);
16     if (self) {
17        self->_dataProvider=O2DataProviderRetain(dataProvider);
18        self->_data=O2DataProviderCopyData(dataProvider);
19        self->_bytes=CFDataGetBytePtr(self->_data);
20        self->_length=CFDataGetLength(self->_data);
21        self->_position=0;
22     }
23     
24    return self;
27 O2TTFDecoderRef O2TTFDecoderRetain(O2TTFDecoderRef self) {
28    return [self retain];
31 void O2TTFDecoderRelease(O2TTFDecoderRef self) {
32    [self release];
35 static void dump(O2TTFDecoderRef self,NSString *format,...){
36    if(self->_dump){
37     va_list arguments;
38     
39     va_start(arguments,format);
40     NSLogv(format,arguments);
41     va_end(arguments);
42    }
45 #if 0
46 static CFIndex currentPosition(O2TTFDecoderRef self){
47    return self->_position;
50 static void seekToPosition(O2TTFDecoderRef self,CFIndex value){
51    self->_position=value;
53 #endif
55 static uint8_t decode_uint8(O2TTFDecoderRef self){
56    if(self->_position>=self->_length){
57     dump(self,@"overflow");
58     exit(0);
59    }
60    
61    return self->_bytes[self->_position++];
64 static uint16_t decode_uint16(O2TTFDecoderRef self){
65   uint16_t result;
66   
67   result=decode_uint8(self);
68   result<<=8;
69   result|=decode_uint8(self);
70   
71   return result;
74 static int16_t decode_int16(O2TTFDecoderRef self){
75   uint16_t result;
76   
77   result=decode_uint8(self);
78   result<<=8;
79   result|=decode_uint8(self);
80   
81   return result;
85 static uint32_t decode_uint32(O2TTFDecoderRef self){
86   uint32_t result;
87   
88   result=decode_uint8(self);
89   result<<=8;
90   result|=decode_uint8(self);
91   result<<=8;
92   result|=decode_uint8(self);
93   result<<=8;
94   result|=decode_uint8(self);
95   
96   return result;
99 static longDateTime64 decode_longDateTime64(O2TTFDecoderRef self){
100    uint64_t result;
101    
102    result=decode_uint32(self);
103    result<<=32;
104    result|=decode_uint32(self);
105    
106    return result;
109 static Fixed32 decode_Fixed32(O2TTFDecoderRef self){
110    return decode_uint32(self);
113 static FWord16 decode_FWord16(O2TTFDecoderRef self){
114    return decode_uint16(self);
117 void decode_format_0(O2TTFDecoderRef self){
119 void decode_format_2(O2TTFDecoderRef self){
121 void decode_format_4(O2TTFDecoderRef self,O2Glyph **twoLevel){
122    struct segment {
123     uint16_t endCode;
124     uint16_t startCode;
125     uint16_t idDelta;
126     uint16_t idRangePosition;
127    } *segments;
128    
129    uint16_t length=decode_uint16(self);
130    dump(self,@"length=%d",length);
131    uint16_t language=decode_uint16(self);
132    dump(self,@"language=%d",language);
133    uint16_t segCountX2=decode_uint16(self);
134    uint16_t segCount=segCountX2/2;
135    segments=__builtin_alloca(sizeof(struct segment)*segCount);
136    dump(self,@"segCountX2=%d",segCountX2);
137    uint16_t searchRange=decode_uint16(self);
138    dump(self,@"searchRange=%d",searchRange);
139    uint16_t entrySelector=decode_uint16(self);
140    dump(self,@"entrySelector=%d",entrySelector);
141    uint16_t rangeShift=decode_uint16(self);
142    dump(self,@"rangeShift=%d",rangeShift);
143    uint16_t i;
144    
145    for(i=0;i<segCount;i++){
146     uint16_t endCode=decode_uint16(self);
147     dump(self,@"endCode[%d]=%x",i,endCode);
148     segments[i].endCode=endCode;
149    }
150    
151    uint16_t reservedPad=decode_uint16(self);
152    dump(self,@"reservedPad=%d",reservedPad);
153    
154    for(i=0;i<segCount;i++){
155     uint16_t startCode=decode_uint16(self);
156     dump(self,@"startCode[%d]=%x",i,startCode);
157     segments[i].startCode=startCode;
158    }
159    
160    for(i=0;i<segCount;i++){
161     uint16_t idDelta=decode_uint16(self);
162     dump(self,@"idDelta[%d]=%x",i,idDelta);
163     
164     segments[i].idDelta=idDelta;
165    }
167    for(i=0;i<segCount;i++){
168     uint16_t position=self->_position;
169     uint16_t idRangeOffset=decode_uint16(self);
170     
171     if(idRangeOffset==0)
172      segments[i].idRangePosition=0;
173     else
174      segments[i].idRangePosition=position+idRangeOffset;
175     
176     dump(self,@"idRangeOffset[%d]=%x",i,idRangeOffset);
177    }
178    
179    for(i=0;i<segCount && segments[i].endCode!=0xFFFF;i++){
180     uint16_t code=segments[i].startCode;
182     if(segments[i].idRangePosition==0){
183      for(;code<=segments[i].endCode;code++){
184       uint16_t glyph=segments[i].idDelta+code;
185       uint8_t  group=code>>8;
186       uint8_t  index=code&0xFF;
187       
188       if(twoLevel[group]==NULL)
189        twoLevel[group]=NSZoneCalloc(NULL,256,sizeof(O2Glyph));
190        
191       twoLevel[group][index]=glyph;      
192      }
193     }
194     else {
195      self->_position=segments[i].idRangePosition;
196      
197      for(;code<=segments[i].endCode;code++){
198       uint16_t glyph=decode_uint16(self);
199       uint8_t  group=code>>8;
200       uint8_t  index=code&0xFF;
201       
202       if(twoLevel[group]==NULL)
203        twoLevel[group]=NSZoneCalloc(NULL,256,sizeof(O2Glyph));
204        
205       twoLevel[group][index]=glyph;      
206      }
207     }
208    }
210 void decode_format_6(O2TTFDecoderRef self){
213 void decode_subtable(O2TTFDecoderRef self,O2Glyph **twoLevel){
214    uint16_t platformID=decode_uint16(self);
215    dump(self,@"platformID=%d",platformID);
216    uint16_t platformSpecificID=decode_uint16(self);
217    dump(self,@"platformSpecificID=%d",platformSpecificID);
218    uint32_t offset=decode_uint32(self);
219    dump(self,@"offset=%d",offset);
220    
221    CFIndex save=self->_position;
222    self->_position=offset;
223    uint16_t format=decode_uint16(self);
224    dump(self,@"format=%d",format);
225    
226    switch(format){
227    
228     case 0:
229      decode_format_0(self);
230      break;
231      
232     case 2:
233      decode_format_2(self);
234      break;
235      
236     case 4:
237      decode_format_4(self,twoLevel);
238      break;
239      
240     case 6:
241      decode_format_6(self);
242      break;
243      
244     default:
245      dump(self,@"unknown format %d",format);
246      break;
247      
248    }
249    
250    self->_position=save;
253 O2Glyph **O2TTFecoderTwoLevelUnicode_cmap(O2TTFDecoderRef self){
254    O2Glyph **twoLevel=NSZoneCalloc(NULL,256,sizeof(O2Glyph *));
255    
256    uint16_t version=decode_uint16(self);
257    dump(self,@"version=%d",version);
258    uint16_t i,subTableCount=decode_uint16(self);
259    dump(self,@"subTableCount=%d",subTableCount);
260    
261    for(i=0;i<subTableCount;i++){
262     decode_subtable(self,twoLevel);
263    }
264    
265    return twoLevel;
268 BOOL seekToTable(O2TTFDecoderRef self,uint32_t seekToTag){
269    self->_position=0;
270    uint32_t scaler=decode_uint32(self);
271    
272    if(scaler!=0x00010000 && scaler!=0x74727565){
273     dump(self,@"invalid scaler=%08X",scaler);
274     return NO;
275    }
277    uint16_t numTables=decode_uint16(self);
278    uint16_t searchRange=decode_uint16(self);
279    uint16_t entrySelector=decode_uint16(self);
280    uint16_t rangeShift=decode_uint16(self);
281    int i;
282    
283    for(i=0;i<numTables;i++){
284     uint32_t tag=decode_uint32(self);
285     uint32_t checkSum=decode_uint32(self);
286     uint32_t offset=decode_uint32(self);
287     uint32_t length=decode_uint32(self);
289     if(tag==seekToTag){
290      self->_position=offset;
291      return YES;
292     }
293    }
294    
295    dump(self,@"unable to find tag %c%c%c%c",seekToTag>>24,(seekToTag>>16)&0xFF,(seekToTag>>8)&0xFF,seekToTag&0xFF);
296    return NO;
298 static struct {
299 // FIXME: remove the glyph entry, pointless
300     O2Glyph   glyph;
301     NSString *name;
302    } MacintoshNameMapping[258]={
303     { 0,@".notdef" },
304     { 1,@".null" },
305     { 2,@"nonmarkingreturn" },
306     { 3,@"space" },
307     { 4,@"exclam" },
308     { 5,@"quotedbl" },
309     { 6,@"numbersign" },
310     { 7,@"dollar" },
311     { 8,@"percent" },
312     { 9,@"ampersand" },
313     { 10,@"quotesingle" },
314     { 11,@"parenleft" },
315     { 12,@"parenright" },
316     { 13,@"asterisk" },
317     { 14,@"plus" },
318     { 15,@"comma" },
319     { 16,@"hyphen" },
320     { 17,@"period" },
321     { 18,@"slash" },
322     { 19,@"zero" },
323     { 20,@"one" },
324     { 21,@"two" },
325     { 22,@"three" },
326     { 23,@"four" },
327     { 24,@"five" },
328     { 25,@"six" },
329     { 26,@"seven" },
330     { 27,@"eight" },
331     { 28,@"nine" },
332     { 29,@"colon" },
333     { 30,@"semicolon" },
334     { 31,@"less" },
335     { 32,@"equal" },
336     { 33,@"greater" },
337     { 34,@"question" },
338     { 35,@"at" },
339     { 36,@"A" },
340     { 37,@"B" },
341     { 38,@"C" },
342     { 39,@"D" },
343     { 40,@"E" },
344     { 41,@"F" },
345     { 42,@"G" },
346     { 43,@"H" },
347     { 44,@"I" },
348     { 45,@"J" },
349     { 46,@"K" },
350     { 47,@"L" },
351     { 48,@"M" },
352     { 49,@"N" },
353     { 50,@"O" },
354     { 51,@"P" },
355     { 52,@"Q" },
356     { 53,@"R" },
357     { 54,@"S" },
358     { 55,@"T" },
359     { 56,@"U" },
360     { 57,@"V" },
361     { 58,@"W" },
362     { 59,@"X" },
363     { 60,@"Y" },
364     { 61,@"Z" },
365     { 62,@"bracketleft" },
366     { 63,@"backslash" },
367     { 64,@"bracketright" },
368     { 65,@"asciicircum" },
369     { 66,@"underscore" },
370     { 67,@"grave" },
371     { 68,@"a" },
372     { 69,@"b" },
373     { 70,@"c" },
374     { 71,@"d" },
375     { 72,@"e" },
376     { 73,@"f" },
377     { 74,@"g" },
378     { 75,@"h" },
379     { 76,@"i" },
380     { 77,@"j" },
381     { 78,@"k" },
382     { 79,@"l" },
383     { 80,@"m" },
384     { 81,@"n" },
385     { 82,@"o" },
386     { 83,@"p" },
387     { 84,@"q" },
388     { 85,@"r" },
389     { 86,@"s" },
390     { 87,@"t" },
391     { 88,@"u" },
392     { 89,@"v" },
393     { 90,@"w" },
394     { 91,@"x" },
395     { 92,@"y" },
396     { 93,@"z" },
397     { 94,@"braceleft" },
398     { 95,@"bar" },
399     { 96,@"braceright" },
400     { 97,@"asciitilde" },
401     { 98,@"Adieresis" },
402     { 99,@"Aring" },
403     { 100,@"Ccedilla" },
404     { 101,@"Eacute" },
405     { 102,@"Ntilde" },
406     { 103,@"Odieresis" },
407     { 104,@"Udieresis" },
408     { 105,@"aacute" },
409     { 106,@"agrave" },
410     { 107,@"acircumflex" },
411     { 108,@"adieresis" },
412     { 109,@"atilde" },
413     { 110,@"aring" },
414     { 111,@"ccedilla" },
415     { 112,@"eacute" },
416     { 113,@"egrave" },
417     { 114,@"ecircumflex" },
418     { 115,@"edieresis" },
419     { 116,@"iacute" },
420     { 117,@"igrave" },
421     { 118,@"icircumflex" },
422     { 119,@"idieresis" },
423     { 120,@"ntilde" },
424     { 121,@"oacute" },
425     { 122,@"ograve" },
426     { 123,@"ocircumflex" },
427     { 124,@"odieresis" },
428     { 125,@"otilde" },
429     { 126,@"uacute" },
430     { 127,@"ugrave" },
431     { 128,@"ucircumflex" },
432     { 129,@"udieresis" },
433     { 130,@"dagger" },
434     { 131,@"degree" },
435     { 132,@"cent" },
436     { 133,@"sterling" },
437     { 134,@"section" },
438     { 135,@"bullet" },
439     { 136,@"paragraph" },
440     { 137,@"germandbls" },
441     { 138,@"registered" },
442     { 139,@"copyright" },
443     { 140,@"trademark" },
444     { 141,@"acute" },
445     { 142,@"dieresis" },
446     { 143,@"notequal" },
447     { 144,@"AE" },
448     { 145,@"Oslash" },
449     { 146,@"infinity" },
450     { 147,@"plusminus" },
451     { 148,@"lessequal" },
452     { 149,@"greaterequal" },
453     { 150,@"yen" },
454     { 151,@"mu" },
455     { 152,@"partialdiff" },
456     { 153,@"summation" },
457     { 154,@"product" },
458     { 155,@"pi" },
459     { 156,@"integral" },
460     { 157,@"ordfeminine" },
461     { 158,@"ordmasculine" },
462     { 159,@"Omega" },
463     { 160,@"ae" },
464     { 161,@"oslash" },
465     { 162,@"questiondown" },
466     { 163,@"exclamdown" },
467     { 164,@"logicalnot" },
468     { 165,@"radical" },
469     { 166,@"florin" },
470     { 167,@"approxequal" },
471     { 168,@"Delta" },
472     { 169,@"guillemotleft" },
473     { 170,@"guillemotright" },
474     { 171,@"ellipsis" },
475     { 172,@"nonbreakingspace" },
476     { 173,@"Agrave" },
477     { 174,@"Atilde" },
478     { 175,@"Otilde" },
479     { 176,@"OE" },
480     { 177,@"oe" },
481     { 178,@"endash" },
482     { 179,@"emdash" },
483     { 180,@"quotedblleft" },
484     { 181,@"quotedblright" },
485     { 182,@"quoteleft" },
486     { 183,@"quoteright" },
487     { 184,@"divide" },
488     { 185,@"lozenge" },
489     { 186,@"ydieresis" },
490     { 187,@"Ydieresis" },
491     { 188,@"fraction" },
492     { 189,@"currency" },
493     { 190,@"guilsinglleft" },
494     { 191,@"guilsinglright" },
495     { 192,@"fi" },
496     { 193,@"fl" },
497     { 194,@"daggerdbl" },
498     { 195,@"periodcentered" },
499     { 196,@"quotesinglbase" },
500     { 197,@"quotedblbase" },
501     { 198,@"perthousand" },
502     { 199,@"Acircumflex" },
503     { 200,@"Ecircumflex" },
504     { 201,@"Aacute" },
505     { 202,@"Edieresis" },
506     { 203,@"Egrave" },
507     { 204,@"Iacute" },
508     { 205,@"Icircumflex" },
509     { 206,@"Idieresis" },
510     { 207,@"Igrave" },
511     { 208,@"Oacute" },
512     { 209,@"Ocircumflex" },
513     { 210,@"apple" },
514     { 211,@"Ograve" },
515     { 212,@"Uacute" },
516     { 213,@"Ucircumflex" },
517     { 214,@"Ugrave" },
518     { 215,@"dotlessi" },
519     { 216,@"circumflex" },
520     { 217,@"tilde" },
521     { 218,@"macron" },
522     { 219,@"breve" },
523     { 220,@"dotaccent" },
524     { 221,@"ring" },
525     { 222,@"cedilla" },
526     { 223,@"hungarumlaut" },
527     { 224,@"ogonek" },
528     { 225,@"caron" },
529     { 226,@"Lslash" },
530     { 227,@"lslash" },
531     { 228,@"Scaron" },
532     { 229,@"scaron" },
533     { 230,@"Zcaron" },
534     { 231,@"zcaron" },
535     { 232,@"brokenbar" },
536     { 233,@"Eth" },
537     { 234,@"eth" },
538     { 235,@"Yacute" },
539     { 236,@"yacute" },
540     { 237,@"Thorn" },
541     { 238,@"thorn" },
542     { 239,@"minus" },
543     { 240,@"multiply" },
544     { 241,@"onesuperior" },
545     { 242,@"twosuperior" },
546     { 243,@"threesuperior" },
547     { 244,@"onehalf" },
548     { 245,@"onequarter" },
549     { 246,@"threequarters" },
550     { 247,@"franc" },
551     { 248,@"Gbreve" },
552     { 249,@"gbreve" },
553     { 250,@"Idotaccent" },
554     { 251,@"Scedilla" },
555     { 252,@"scedilla" },
556     { 253,@"Cacute" },
557     { 254,@"cacute" },
558     { 255,@"Ccaron" },
559     { 256,@"ccaron" },
560     { 257,@"dcroat" },
561    };
563 static void loadMacintoshNameMapping(NSMapTable *table){
564    NSInteger i;
565    
566    for(i=0;i<258;i++)
567     NSMapInsert(table,MacintoshNameMapping[i].name,(void *)i);
570 NSMapTable *O2TTFDecoderGetPostScriptNameMapTable(O2TTFDecoderRef self,int *numberOfGlyphs){
571    NSMapTable *result=NSCreateMapTable(NSObjectMapKeyCallBacks,NSIntegerMapValueCallBacks,258);
573    if(!seekToTable(self,'post'))
574     return NULL;
576    Fixed32 format=decode_Fixed32(self);
577    Fixed32 italicAngle=decode_Fixed32(self);
578    FWord16 underlinePosition=decode_FWord16(self);
579    FWord16 underlineThickness=decode_FWord16(self);
580    uint32_t isFixedPitch=decode_uint32(self);
581    uint32_t minMemType42=decode_uint32(self);
582    uint32_t maxMemType42=decode_uint32(self);
583    uint32_t minMemType1=decode_uint32(self);
584    uint32_t maxMemType1=decode_uint32(self);
585       
586    switch(format){
587    
588     default:
589      NSLog(@"unimplemented 'post' format %08X",format);
590      return NULL;
592     case 0x00010000:;
593      loadMacintoshNameMapping(result);
594      break;
595      
596     case 0x00020000:;
597      uint16_t numberOfGlyphs=decode_uint16(self);
598      int      i;
599      uint16_t maxIndex=0;
600      uint16_t glyphNameIndex[numberOfGlyphs];
601      
602      for(i=0;i<numberOfGlyphs;i++){
603       glyphNameIndex[i]=decode_uint16(self);
604       
605       maxIndex=MAX(maxIndex,glyphNameIndex[i]);
606      }
607      maxIndex-=258;
608      maxIndex++;
609      NSString *names[maxIndex];
610      
611      for(i=0;i<maxIndex;i++){
612       uint8_t length=decode_uint8(self);
613       uint8_t buffer[length];
614       int     count=0;
615       
616       for(count=0;count<length;count++)
617        buffer[count]=decode_uint8(self);
618        
619       names[i]=[[NSString alloc] initWithBytes:buffer length:count encoding:NSASCIIStringEncoding];
620      }
622      for(i=0;i<numberOfGlyphs;i++){
623       uint16_t nameIndex=glyphNameIndex[i];
624       
625       if(nameIndex<=257)
626        NSMapInsert(result,MacintoshNameMapping[nameIndex].name,(void *)i);
627       else {
628        nameIndex-=258;
629        NSMapInsert(result,names[nameIndex],(void *)i);
630       } 
631      }
632      
633      for(i=0;i<maxIndex;i++)
634       [names[i] release];
635      break;
636      
637    }
638    
639    return result;
642 int O2TTFDecoderGetOffsetsAreLong(O2TTFDecoderRef self) {
643    if(!seekToTable(self,'head'))
644     return 0;
646    Fixed32  version=decode_Fixed32(self);
647    Fixed32  fontRevision=decode_Fixed32(self);
648    uint32_t checkSumAdjustment=decode_uint32(self);
649    uint32_t magicNumber=decode_uint32(self);
650    uint16_t flags=decode_uint16(self);
651    uint16_t unitsPerEm=decode_uint16(self);
652    longDateTime64 created=decode_longDateTime64(self);
653    longDateTime64 modified=decode_longDateTime64(self);
654    FWord16 xMin=decode_FWord16(self);
655    FWord16 yMin=decode_FWord16(self);
656    FWord16 xMax=decode_FWord16(self);
657    FWord16 yMax=decode_FWord16(self);
658    uint16_t macStyle=decode_uint16(self);
659    uint16_t lowestRecPPEM=decode_uint16(self);
660    int16_t fontDirectionHint=decode_int16(self);
661    int16_t indexToLocFormat=decode_int16(self);
662    int16_t glyphDataFormat=decode_int16(self);
664    return indexToLocFormat;
667 int *O2TTFDecoderGetGlyphLocations(O2TTFDecoderRef self,int numberOfGlyphs) {
668    int *result=NSZoneMalloc(NULL,sizeof(int)*numberOfGlyphs);
669    
670    if(O2TTFDecoderGetOffsetsAreLong(self)){
671     if(!seekToTable(self,'loca'))
672      return NULL;
673      
674     int i;
675     for(i=0;i<numberOfGlyphs;i++)
676      result[i]=decode_uint32(self);
677      
678    }
679    else {
680     if(!seekToTable(self,'loca'))
681      return NULL;
682      
683     int i;
684     for(i=0;i<numberOfGlyphs;i++)
685      result[i]=decode_uint16(self);
686    }
687    return result;
690 O2PathRef O2TTFDecoderGetGlyphOutline(O2TTFDecoderRef self,int glyphLocation) {
691    O2PathRef result=O2PathCreateMutable();
692    
693     if(!seekToTable(self,'glyf'))
694      return NULL;
696    self->_position+=glyphLocation;
697    
698    int16_t numberOfContours=decode_int16(self);
699    
700    if(numberOfContours>=0){
701     uint16_t endPtsOfContours[numberOfContours];
702     int i;
703     
704     for(i=0;i<numberOfContours;i++)
705      endPtsOfContours[i]=decode_uint16(self);
707     uint16_t instructionLength=decode_uint16(self);
708     uint8_t  instructions[instructionLength];
709     
710     for(i=0;i<instructionLength;i++)
711      instructions[i]=decode_uint8(self);
712     
713     
714    }
715    else if(numberOfContours==-1){
716    }
717    else {
718     NSLog(@"invalid numberOfContours=%d",numberOfContours);
719    }
720    
721    return result;
724 void O2TTFDecoderGetNameTable(O2TTFDecoderRef self) {
725    if(!seekToTable(self,'name')){
726     NSLog(@"TrueType error: No name table");
727     return;
728    }
730    int      stringTable=self->_position;
731    
732    uint16_t format=decode_uint16(self);
733    uint16_t i,count=decode_uint16(self);
734    uint16_t stringOffset=decode_uint16(self);
736    stringTable+=stringOffset;
737    
738    for(i=0;i<count;i++){
739     uint16_t platformID=decode_uint16(self);
740     /*uint16_t platformSpecificID=*/decode_uint16(self);
741     uint16_t languageID=decode_uint16(self);
742     uint16_t nameID=decode_uint16(self);
743     uint16_t length=decode_uint16(self);
744     uint16_t offset=decode_uint16(self);
745     
746     CFIndex location=stringTable+offset;
747     
748     NSLog(@"platformID=%d,languageId=%d,nameID=%d",platformID,languageID,nameID);
749     
750     NSLog(@"position=%ld,stringOffset=%d,offset=%d",self->_position,stringOffset,offset);
751     
752     NSString *string=[NSString stringWithCString:(const char *)self->_bytes+location length:length];
753     
754     NSLog(@"platformID=%d,languageID=%d,string=%@",platformID,languageID,string);
755    }
760 @end