Coverage Report

Created: 2026-03-15 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xpdf-4.06/fofi/FoFiIdentifier.cc
Line
Count
Source
1
//========================================================================
2
//
3
// FoFiIdentifier.cc
4
//
5
// Copyright 2009 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#include <stdio.h>
12
#include <string.h>
13
#include <limits.h>
14
#include "gtypes.h"
15
#include "gmem.h"
16
#include "gmempp.h"
17
#include "GString.h"
18
#include "GList.h"
19
#include "FoFiIdentifier.h"
20
21
//------------------------------------------------------------------------
22
23
class Reader {
24
public:
25
26
21.0k
  virtual ~Reader() {}
27
28
  // Read one byte.  Returns -1 if past EOF.
29
  virtual int getByte(int pos) = 0;
30
31
  // Read a big-endian unsigned 16-bit integer.  Fills in *val and
32
  // returns true if successful.
33
  virtual GBool getU16BE(int pos, int *val) = 0;
34
35
  // Read a big-endian unsigned 32-bit integer.  Fills in *val and
36
  // returns true if successful.
37
  virtual GBool getU32BE(int pos, Guint *val) = 0;
38
39
  // Read a little-endian unsigned 32-bit integer.  Fills in *val and
40
  // returns true if successful.
41
  virtual GBool getU32LE(int pos, Guint *val) = 0;
42
43
  // Read a big-endian unsigned <size>-byte integer, where 1 <= size
44
  // <= 4.  Fills in *val and returns true if successful.
45
  virtual GBool getUVarBE(int pos, int size, Guint *val) = 0;
46
47
  // Compare against a string.  Returns true if equal.
48
  virtual GBool cmp(int pos, const char *s) = 0;
49
50
};
51
52
//------------------------------------------------------------------------
53
54
class MemReader: public Reader {
55
public:
56
57
  static MemReader *make(char *bufA, int lenA);
58
  virtual ~MemReader();
59
  virtual int getByte(int pos);
60
  virtual GBool getU16BE(int pos, int *val);
61
  virtual GBool getU32BE(int pos, Guint *val);
62
  virtual GBool getU32LE(int pos, Guint *val);
63
  virtual GBool getUVarBE(int pos, int size, Guint *val);
64
  virtual GBool cmp(int pos, const char *s);
65
66
private:
67
68
  MemReader(char *bufA, int lenA);
69
70
  char *buf;
71
  int len;
72
};
73
74
0
MemReader *MemReader::make(char *bufA, int lenA) {
75
0
  return new MemReader(bufA, lenA);
76
0
}
77
78
0
MemReader::MemReader(char *bufA, int lenA) {
79
0
  buf = bufA;
80
0
  len = lenA;
81
0
}
82
83
0
MemReader::~MemReader() {
84
0
}
85
86
0
int MemReader::getByte(int pos) {
87
0
  if (pos < 0 || pos >= len) {
88
0
    return -1;
89
0
  }
90
0
  return buf[pos] & 0xff;
91
0
}
92
93
0
GBool MemReader::getU16BE(int pos, int *val) {
94
0
  if (pos < 0 || pos > len - 2) {
95
0
    return gFalse;
96
0
  }
97
0
  *val = ((buf[pos] & 0xff) << 8) +
98
0
         (buf[pos+1] & 0xff);
99
0
  return gTrue;
100
0
}
101
102
0
GBool MemReader::getU32BE(int pos, Guint *val) {
103
0
  if (pos < 0 || pos > len - 4) {
104
0
    return gFalse;
105
0
  }
106
0
  *val = ((buf[pos] & 0xff) << 24) +
107
0
         ((buf[pos+1] & 0xff) << 16) +
108
0
         ((buf[pos+2] & 0xff) << 8) +
109
0
         (buf[pos+3] & 0xff);
110
0
  return gTrue;
111
0
}
112
113
0
GBool MemReader::getU32LE(int pos, Guint *val) {
114
0
  if (pos < 0 || pos > len - 4) {
115
0
    return gFalse;
116
0
  }
117
0
  *val = (buf[pos] & 0xff) +
118
0
         ((buf[pos+1] & 0xff) << 8) +
119
0
         ((buf[pos+2] & 0xff) << 16) +
120
0
         ((buf[pos+3] & 0xff) << 24);
121
0
  return gTrue;
122
0
}
123
124
0
GBool MemReader::getUVarBE(int pos, int size, Guint *val) {
125
0
  int i;
126
127
0
  if (size < 1 || size > 4 || pos < 0 || pos > len - size) {
128
0
    return gFalse;
129
0
  }
130
0
  *val = 0;
131
0
  for (i = 0; i < size; ++i) {
132
0
    *val = (*val << 8) + (buf[pos + i] & 0xff);
133
0
  }
134
0
  return gTrue;
135
0
}
136
137
0
GBool MemReader::cmp(int pos, const char *s) {
138
0
  int n;
139
140
0
  n = (int)strlen(s);
141
0
  if (pos < 0 || len < n || pos > len - n) {
142
0
    return gFalse;
143
0
  }
144
0
  return !memcmp(buf + pos, s, n);
145
0
}
146
147
//------------------------------------------------------------------------
148
149
class FileReader: public Reader {
150
public:
151
152
  static FileReader *make(char *fileName);
153
  virtual ~FileReader();
154
  virtual int getByte(int pos);
155
  virtual GBool getU16BE(int pos, int *val);
156
  virtual GBool getU32BE(int pos, Guint *val);
157
  virtual GBool getU32LE(int pos, Guint *val);
158
  virtual GBool getUVarBE(int pos, int size, Guint *val);
159
  virtual GBool cmp(int pos, const char *s);
160
161
private:
162
163
  FileReader(FILE *fA);
164
  GBool fillBuf(int pos, int len);
165
166
  FILE *f;
167
  char buf[1024];
168
  int bufPos, bufLen;
169
};
170
171
0
FileReader *FileReader::make(char *fileName) {
172
0
  FILE *fA;
173
174
0
  if (!(fA = fopen(fileName, "rb"))) {
175
0
    return NULL;
176
0
  }
177
0
  return new FileReader(fA);
178
0
}
179
180
0
FileReader::FileReader(FILE *fA) {
181
0
  f = fA;
182
0
  bufPos = 0;
183
0
  bufLen = 0;
184
0
}
185
186
0
FileReader::~FileReader() {
187
0
  fclose(f);
188
0
}
189
190
0
int FileReader::getByte(int pos) {
191
0
  if (!fillBuf(pos, 1)) {
192
0
    return -1;
193
0
  }
194
0
  return buf[pos - bufPos] & 0xff;
195
0
}
196
197
0
GBool FileReader::getU16BE(int pos, int *val) {
198
0
  if (!fillBuf(pos, 2)) {
199
0
    return gFalse;
200
0
  }
201
0
  *val = ((buf[pos - bufPos] & 0xff) << 8) +
202
0
         (buf[pos - bufPos + 1] & 0xff);
203
0
  return gTrue;
204
0
}
205
206
0
GBool FileReader::getU32BE(int pos, Guint *val) {
207
0
  if (!fillBuf(pos, 4)) {
208
0
    return gFalse;
209
0
  }
210
0
  *val = ((buf[pos - bufPos] & 0xff) << 24) +
211
0
         ((buf[pos - bufPos + 1] & 0xff) << 16) +
212
0
         ((buf[pos - bufPos + 2] & 0xff) << 8) +
213
0
         (buf[pos - bufPos + 3] & 0xff);
214
0
  return gTrue;
215
0
}
216
217
0
GBool FileReader::getU32LE(int pos, Guint *val) {
218
0
  if (!fillBuf(pos, 4)) {
219
0
    return gFalse;
220
0
  }
221
0
  *val = (buf[pos - bufPos] & 0xff) +
222
0
         ((buf[pos - bufPos + 1] & 0xff) << 8) +
223
0
         ((buf[pos - bufPos + 2] & 0xff) << 16) +
224
0
         ((buf[pos - bufPos + 3] & 0xff) << 24);
225
0
  return gTrue;
226
0
}
227
228
0
GBool FileReader::getUVarBE(int pos, int size, Guint *val) {
229
0
  int i;
230
231
0
  if (size < 1 || size > 4 || !fillBuf(pos, size)) {
232
0
    return gFalse;
233
0
  }
234
0
  *val = 0;
235
0
  for (i = 0; i < size; ++i) {
236
0
    *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff);
237
0
  }
238
0
  return gTrue;
239
0
}
240
241
0
GBool FileReader::cmp(int pos, const char *s) {
242
0
  int n;
243
244
0
  n = (int)strlen(s);
245
0
  if (!fillBuf(pos, n)) {
246
0
    return gFalse;
247
0
  }
248
0
  return !memcmp(buf - bufPos + pos, s, n);
249
0
}
250
251
0
GBool FileReader::fillBuf(int pos, int len) {
252
0
  if (pos < 0 || len < 0 || len > (int)sizeof(buf) ||
253
0
      pos > INT_MAX - (int)sizeof(buf)) {
254
0
    return gFalse;
255
0
  }
256
0
  if (pos >= bufPos && pos + len <= bufPos + bufLen) {
257
0
    return gTrue;
258
0
  }
259
0
  if (fseek(f, pos, SEEK_SET)) {
260
0
    return gFalse;
261
0
  }
262
0
  bufPos = pos;
263
0
  bufLen = (int)fread(buf, 1, sizeof(buf), f);
264
0
  if (bufLen < len) {
265
0
    return gFalse;
266
0
  }
267
0
  return gTrue;
268
0
}
269
270
//------------------------------------------------------------------------
271
272
class StreamReader: public Reader {
273
public:
274
275
  static StreamReader *make(int (*getCharA)(void *data), void *dataA);
276
  virtual ~StreamReader();
277
  virtual int getByte(int pos);
278
  virtual GBool getU16BE(int pos, int *val);
279
  virtual GBool getU32BE(int pos, Guint *val);
280
  virtual GBool getU32LE(int pos, Guint *val);
281
  virtual GBool getUVarBE(int pos, int size, Guint *val);
282
  virtual GBool cmp(int pos, const char *s);
283
284
private:
285
286
  StreamReader(int (*getCharA)(void *data), void *dataA);
287
  GBool fillBuf(int pos, int len);
288
289
  int (*getChar)(void *data);
290
  void *data;
291
  int streamPos;
292
  char buf[1024];
293
  int bufPos, bufLen;
294
};
295
296
21.0k
StreamReader *StreamReader::make(int (*getCharA)(void *data), void *dataA) {
297
21.0k
  return new StreamReader(getCharA, dataA);
298
21.0k
}
299
300
21.0k
StreamReader::StreamReader(int (*getCharA)(void *data), void *dataA) {
301
21.0k
  getChar = getCharA;
302
21.0k
  data = dataA;
303
21.0k
  streamPos = 0;
304
21.0k
  bufPos = 0;
305
21.0k
  bufLen = 0;
306
21.0k
}
307
308
21.0k
StreamReader::~StreamReader() {
309
21.0k
}
310
311
258k
int StreamReader::getByte(int pos) {
312
258k
  if (!fillBuf(pos, 1)) {
313
13.5k
    return -1;
314
13.5k
  }
315
244k
  return buf[pos - bufPos] & 0xff;
316
258k
}
317
318
8.01k
GBool StreamReader::getU16BE(int pos, int *val) {
319
8.01k
  if (!fillBuf(pos, 2)) {
320
8
    return gFalse;
321
8
  }
322
8.00k
  *val = ((buf[pos - bufPos] & 0xff) << 8) +
323
8.00k
         (buf[pos - bufPos + 1] & 0xff);
324
8.00k
  return gTrue;
325
8.01k
}
326
327
2.65k
GBool StreamReader::getU32BE(int pos, Guint *val) {
328
2.65k
  if (!fillBuf(pos, 4)) {
329
0
    return gFalse;
330
0
  }
331
2.65k
  *val = ((buf[pos - bufPos] & 0xff) << 24) +
332
2.65k
         ((buf[pos - bufPos + 1] & 0xff) << 16) +
333
2.65k
         ((buf[pos - bufPos + 2] & 0xff) << 8) +
334
2.65k
         (buf[pos - bufPos + 3] & 0xff);
335
2.65k
  return gTrue;
336
2.65k
}
337
338
3
GBool StreamReader::getU32LE(int pos, Guint *val) {
339
3
  if (!fillBuf(pos, 4)) {
340
1
    return gFalse;
341
1
  }
342
2
  *val = (buf[pos - bufPos] & 0xff) +
343
2
         ((buf[pos - bufPos + 1] & 0xff) << 8) +
344
2
         ((buf[pos - bufPos + 2] & 0xff) << 16) +
345
2
         ((buf[pos - bufPos + 3] & 0xff) << 24);
346
2
  return gTrue;
347
3
}
348
349
7.90k
GBool StreamReader::getUVarBE(int pos, int size, Guint *val) {
350
7.90k
  int i;
351
352
7.90k
  if (size < 1 || size > 4 || !fillBuf(pos, size)) {
353
8
    return gFalse;
354
8
  }
355
7.89k
  *val = 0;
356
15.8k
  for (i = 0; i < size; ++i) {
357
7.99k
    *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff);
358
7.99k
  }
359
7.89k
  return gTrue;
360
7.90k
}
361
362
79.2k
GBool StreamReader::cmp(int pos, const char *s) {
363
79.2k
  int n;
364
365
79.2k
  n = (int)strlen(s);
366
79.2k
  if (!fillBuf(pos, n)) {
367
40.2k
    return gFalse;
368
40.2k
  }
369
38.9k
  return !memcmp(buf - bufPos + pos, s, n);
370
79.2k
}
371
372
356k
GBool StreamReader::fillBuf(int pos, int len) {
373
356k
  int c;
374
375
356k
  if (pos < 0 || len < 0 || len > (int)sizeof(buf) ||
376
356k
      pos > INT_MAX - (int)sizeof(buf)) {
377
0
    return gFalse;
378
0
  }
379
356k
  if (pos < bufPos) {
380
0
    return gFalse;
381
0
  }
382
383
  // if requested region will not fit in the current buffer...
384
356k
  if (pos + len > bufPos + (int)sizeof(buf)) {
385
386
    // if the start of the requested data is already in the buffer, move
387
    // it to the start of the buffer
388
35.7k
    if (pos < bufPos + bufLen) {
389
0
      bufLen -= pos - bufPos;
390
0
      memmove(buf, buf + (pos - bufPos), bufLen);
391
0
      bufPos = pos;
392
393
    // otherwise discard data from the
394
    // stream until we get to the requested position
395
35.7k
    } else {
396
35.7k
      bufPos += bufLen;
397
35.7k
      bufLen = 0;
398
1.24M
      while (bufPos < pos) {
399
1.24M
  if ((c = (*getChar)(data)) < 0) {
400
35.4k
    return gFalse;
401
35.4k
  }
402
1.20M
  ++bufPos;
403
1.20M
      }
404
35.7k
    }
405
35.7k
  }
406
407
  // read the rest of the requested data
408
889k
  while (bufPos + bufLen < pos + len) {
409
587k
    if ((c = (*getChar)(data)) < 0) {
410
18.2k
      return gFalse;
411
18.2k
    }
412
569k
    buf[bufLen++] = (char)c;
413
569k
  }
414
415
302k
  return gTrue;
416
320k
}
417
418
//------------------------------------------------------------------------
419
420
static FoFiIdentifierType identify(Reader *reader);
421
static FoFiIdentifierType identifyOpenType(Reader *reader);
422
static FoFiIdentifierType identifyCFF(Reader *reader, int start);
423
424
0
FoFiIdentifierType FoFiIdentifier::identifyMem(char *file, int len) {
425
0
  MemReader *reader;
426
0
  FoFiIdentifierType type;
427
428
0
  if (!(reader = MemReader::make(file, len))) {
429
0
    return fofiIdError;
430
0
  }
431
0
  type = identify(reader);
432
0
  delete reader;
433
0
  return type;
434
0
}
435
436
0
FoFiIdentifierType FoFiIdentifier::identifyFile(char *fileName) {
437
0
  FileReader *reader;
438
0
  FoFiIdentifierType type;
439
0
  int n;
440
441
0
  if (!(reader = FileReader::make(fileName))) {
442
0
    return fofiIdError;
443
0
  }
444
0
  type = identify(reader);
445
0
  delete reader;
446
447
  // Mac OS X dfont files don't have any sort of header or magic number,
448
  // so look at the file name extension
449
0
  if (type == fofiIdUnknown) {
450
0
    n = (int)strlen(fileName);
451
0
    if (n >= 6 && !strcmp(fileName + n - 6, ".dfont")) {
452
0
      type = fofiIdDfont;
453
0
    }
454
0
  }
455
456
0
  return type;
457
0
}
458
459
FoFiIdentifierType FoFiIdentifier::identifyStream(int (*getChar)(void *data),
460
21.0k
              void *data) {
461
21.0k
  StreamReader *reader;
462
21.0k
  FoFiIdentifierType type;
463
464
21.0k
  if (!(reader = StreamReader::make(getChar, data))) {
465
0
    return fofiIdError;
466
0
  }
467
21.0k
  type = identify(reader);
468
21.0k
  delete reader;
469
21.0k
  return type;
470
21.0k
}
471
472
21.0k
static FoFiIdentifierType identify(Reader *reader) {
473
21.0k
  Guint n;
474
475
  //----- PFA
476
21.0k
  if (reader->cmp(0, "%!PS-AdobeFont-1") ||
477
19.6k
      reader->cmp(0, "%!FontType1")) {
478
1.46k
    return fofiIdType1PFA;
479
1.46k
  }
480
481
  //----- PFB
482
19.5k
  if (reader->getByte(0) == 0x80 &&
483
6
      reader->getByte(1) == 0x01 &&
484
3
      reader->getU32LE(2, &n)) {
485
2
    if ((n >= 16 && reader->cmp(6, "%!PS-AdobeFont-1")) ||
486
1
  (n >= 11 && reader->cmp(6, "%!FontType1"))) {
487
1
      return fofiIdType1PFB;
488
1
    }
489
2
  }
490
491
  //----- TrueType
492
19.5k
  if ((reader->getByte(0) == 0x00 &&
493
6.60k
       reader->getByte(1) == 0x01 &&
494
6.39k
       reader->getByte(2) == 0x00 &&
495
6.38k
       reader->getByte(3) == 0x00) ||
496
13.1k
      (reader->getByte(0) == 0x74 && // 'true'
497
1.77k
       reader->getByte(1) == 0x72 &&
498
1.77k
       reader->getByte(2) == 0x75 &&
499
8.14k
       reader->getByte(3) == 0x65)) {
500
8.14k
    return fofiIdTrueType;
501
8.14k
  }
502
11.3k
  if (reader->getByte(0) == 0x74 && // 'ttcf'
503
9
      reader->getByte(1) == 0x74 &&
504
1
      reader->getByte(2) == 0x63 &&
505
0
      reader->getByte(3) == 0x66) {
506
0
    return fofiIdTrueTypeCollection;
507
0
  }
508
509
  //----- OpenType
510
11.3k
  if (reader->getByte(0) == 0x4f && // 'OTTO
511
2.68k
      reader->getByte(1) == 0x54 &&
512
2.67k
      reader->getByte(2) == 0x54 &&
513
2.67k
      reader->getByte(3) == 0x4f) {
514
2.66k
    return identifyOpenType(reader);
515
2.66k
  }
516
517
  //----- CFF
518
8.73k
  if (reader->getByte(0) == 0x01 &&
519
3.08k
      reader->getByte(1) == 0x00) {
520
2.87k
    return identifyCFF(reader, 0);
521
2.87k
  }
522
  // some tools embed CFF fonts with an extra whitespace char at the
523
  // beginning
524
5.85k
  if (reader->getByte(1) == 0x01 &&
525
441
      reader->getByte(2) == 0x00) {
526
225
    return identifyCFF(reader, 1);
527
225
  }
528
529
5.63k
  return fofiIdUnknown;
530
5.85k
}
531
532
2.66k
static FoFiIdentifierType identifyOpenType(Reader *reader) {
533
2.66k
  FoFiIdentifierType type;
534
2.66k
  Guint offset;
535
2.66k
  int nTables, i;
536
537
2.66k
  if (!reader->getU16BE(4, &nTables)) {
538
0
    return fofiIdUnknown;
539
0
  }
540
38.5k
  for (i = 0; i < nTables; ++i) {
541
38.5k
    if (reader->cmp(12 + i*16, "CFF ")) {
542
2.65k
      if (reader->getU32BE(12 + i*16 + 8, &offset) &&
543
2.65k
    offset < (Guint)INT_MAX) {
544
22
  type = identifyCFF(reader, (int)offset);
545
22
  if (type == fofiIdCFF8Bit) {
546
0
    type = fofiIdOpenTypeCFF8Bit;
547
22
  } else if (type == fofiIdCFFCID) {
548
0
    type = fofiIdOpenTypeCFFCID;
549
0
  }
550
22
  return type;
551
22
      }
552
2.63k
      return fofiIdUnknown;
553
2.65k
    }
554
38.5k
  }
555
12
  return fofiIdUnknown;
556
2.66k
}
557
558
3.12k
static FoFiIdentifierType identifyCFF(Reader *reader, int start) {
559
3.12k
  Guint offset0, offset1;
560
3.12k
  int hdrSize, offSize0, offSize1, pos, endPos, b0, n;
561
562
  //----- read the header
563
3.12k
  if (reader->getByte(start) != 0x01 ||
564
3.10k
      reader->getByte(start + 1) != 0x00) {
565
22
    return fofiIdUnknown;
566
22
  }
567
3.10k
  if ((hdrSize = reader->getByte(start + 2)) < 0) {
568
7
    return fofiIdUnknown;
569
7
  }
570
3.09k
  if ((offSize0 = reader->getByte(start + 3)) < 1 || offSize0 > 4) {
571
414
    return fofiIdUnknown;
572
414
  }
573
2.67k
  pos = start + hdrSize;
574
2.67k
  if (pos < 0) {
575
0
    return fofiIdUnknown;
576
0
  }
577
578
  //----- skip the name index
579
2.67k
  if (!reader->getU16BE(pos, &n)) {
580
3
    return fofiIdUnknown;
581
3
  }
582
2.67k
  if (n == 0) {
583
20
    pos += 2;
584
2.65k
  } else {
585
2.65k
    if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) {
586
6
      return fofiIdUnknown;
587
6
    }
588
2.65k
    if (!reader->getUVarBE(pos + 3 + n * offSize1, offSize1, &offset1) ||
589
2.64k
  offset1 > (Guint)INT_MAX) {
590
6
      return fofiIdUnknown;
591
6
    }
592
2.64k
    pos += 3 + (n + 1) * offSize1 + (int)offset1 - 1;
593
2.64k
  }
594
2.66k
  if (pos < 0) {
595
0
    return fofiIdUnknown;
596
0
  }
597
598
  //----- parse the top dict index
599
2.66k
  if (!reader->getU16BE(pos, &n) || n < 1) {
600
26
    return fofiIdUnknown;
601
26
  }
602
2.63k
  if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) {
603
8
    return fofiIdUnknown;
604
8
  }
605
2.63k
  if (!reader->getUVarBE(pos + 3, offSize1, &offset0) ||
606
2.62k
      offset0 > (Guint)INT_MAX ||
607
2.62k
      !reader->getUVarBE(pos + 3 + offSize1, offSize1, &offset1) ||
608
2.62k
      offset1 > (Guint)INT_MAX ||
609
2.62k
      offset0 > offset1) {
610
13
    return fofiIdUnknown;
611
13
  }
612
2.61k
  pos = pos + 3 + (n + 1) * offSize1 + (int)offset0 - 1;
613
2.61k
  endPos = pos + 3 + (n + 1) * offSize1 + (int)offset1 - 1;
614
2.61k
  if (pos < 0 || endPos < 0 || pos > endPos) {
615
0
    return fofiIdUnknown;
616
0
  }
617
  
618
  //----- parse the top dict, look for ROS as first entry
619
  // for a CID font, the top dict starts with:
620
  //     <int> <int> <int> ROS
621
111k
  while (pos >= 0 && pos < endPos) {
622
111k
    b0 = reader->getByte(pos);
623
111k
    if (b0 == 0x1c) {
624
14.2k
      pos += 3;
625
96.9k
    } else if (b0 == 0x1d) {
626
5
      pos += 5;
627
96.9k
    } else if (b0 >= 0xf7 && b0 <= 0xfe) {
628
54.8k
      pos += 2;
629
54.8k
    } else if (b0 >= 0x20 && b0 <= 0xf6) {
630
39.5k
      pos += 1;
631
39.5k
    } else {
632
2.60k
      break;
633
2.60k
    }
634
111k
  }
635
2.61k
  if (pos + 1 < endPos &&
636
2.60k
      reader->getByte(pos) == 12 &&
637
715
      reader->getByte(pos + 1) == 30) {
638
60
    return fofiIdCFFCID;
639
2.55k
  } else {
640
2.55k
    return fofiIdCFF8Bit;
641
2.55k
  }
642
2.61k
}
643
644
//------------------------------------------------------------------------
645
646
static GList *getTTCFontList(FILE *f);
647
static GList *getDfontFontList(FILE *f);
648
649
0
GList *FoFiIdentifier::getFontList(char *fileName) {
650
0
  FILE *f;
651
0
  char buf[4];
652
0
  GList *ret;
653
654
0
  if (!(f = fopen(fileName, "rb"))) {
655
0
    return NULL;
656
0
  }
657
0
  if (fread(buf, 1, 4, f) == 4 &&
658
0
      buf[0] == 0x74 &&    // 'ttcf'
659
0
      buf[1] == 0x74 &&
660
0
      buf[2] == 0x63 &&
661
0
      buf[3] == 0x66) {
662
0
    ret = getTTCFontList(f);
663
0
  } else {
664
0
    ret = getDfontFontList(f);
665
0
  }
666
0
  fclose(f);
667
0
  return ret;
668
0
}
669
670
0
static GList *getTTCFontList(FILE *f) {
671
0
  Guchar buf[12];
672
0
  Guchar *buf2;
673
0
  int fileLength, nFonts;
674
0
  int tabDirOffset, nTables, nameTabOffset, nNames, stringsOffset;
675
0
  int stringPlatform, stringLength, stringOffset;
676
0
  GBool stringUnicode;
677
0
  int i, j;
678
0
  GList *ret;
679
680
0
  fseek(f, 0, SEEK_END);
681
0
  fileLength = (int)ftell(f);
682
0
  if (fileLength < 0) {
683
0
    goto err1;
684
0
  }
685
0
  fseek(f, 8, SEEK_SET);
686
0
  if (fread(buf, 1, 4, f) != 4) {
687
0
    goto err1;
688
0
  }
689
0
  nFonts = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
690
0
  if (nFonts < 0 ||
691
0
      12 + 4 * nFonts > fileLength) {
692
0
    goto err1;
693
0
  }
694
0
  ret = new GList();
695
0
  for (i = 0; i < nFonts; ++i) {
696
0
    fseek(f, 12 + 4 * i, SEEK_SET);
697
0
    if (fread(buf, 1, 4, f) != 4) {
698
0
      goto err2;
699
0
    }
700
0
    tabDirOffset = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
701
0
    if (tabDirOffset < 0 ||
702
0
  tabDirOffset + 12 < 0 ||
703
0
  tabDirOffset + 12 > fileLength) {
704
0
      goto err2;
705
0
    }
706
0
    fseek(f, tabDirOffset, SEEK_SET);
707
0
    if (fread(buf, 1, 12, f) != 12) {
708
0
      goto err2;
709
0
    }
710
0
    nTables = (buf[4] << 8) | buf[5];
711
0
    if (tabDirOffset + 12 + 16 * nTables < 0 ||
712
0
  tabDirOffset + 12 + 16 * nTables > fileLength) {
713
0
      goto err2;
714
0
    }
715
0
    buf2 = (Guchar *)gmallocn(nTables, 16);
716
0
    if ((int)fread(buf2, 1, 16 * nTables, f) != 16 * nTables) {
717
0
      goto err3;
718
0
    }
719
0
    nameTabOffset = 0; // make gcc happy
720
0
    for (j = 0; j < nTables; ++j) {
721
0
      if (buf2[16*j + 0] == 'n' &&
722
0
    buf2[16*j + 1] == 'a' &&
723
0
    buf2[16*j + 2] == 'm' &&
724
0
    buf2[16*j + 3] == 'e') {
725
0
  nameTabOffset = (buf2[16*j + 8] << 24) | (buf2[16*j + 9] << 16) |
726
0
                  (buf2[16*j + 10] << 8) | buf2[16*j + 11];
727
0
  break;
728
0
      }
729
0
    }
730
0
    gfree(buf2);
731
0
    if (j >= nTables) {
732
0
      goto err2;
733
0
    }
734
0
    if (nameTabOffset < 0 ||
735
0
  nameTabOffset + 6 < 0 ||
736
0
  nameTabOffset + 6 > fileLength) {
737
0
      goto err2;
738
0
    }
739
0
    fseek(f, nameTabOffset, SEEK_SET);
740
0
    if (fread(buf, 1, 6, f) != 6) {
741
0
      goto err2;
742
0
    }
743
0
    nNames = (buf[2] << 8) | buf[3];
744
0
    stringsOffset = (buf[4] << 8) | buf[5];
745
0
    if (nameTabOffset + 6 + 12 * nNames < 0 ||
746
0
  nameTabOffset + 6 + 12 * nNames > fileLength ||
747
0
  nameTabOffset + stringsOffset < 0) {
748
0
      goto err2;
749
0
    }
750
0
    buf2 = (Guchar *)gmallocn(nNames, 12);
751
0
    if ((int)fread(buf2, 1, 12 * nNames, f) != 12 * nNames) {
752
0
      goto err3;
753
0
    }
754
0
    for (j = 0; j < nNames; ++j) {
755
0
      if (buf2[12*j + 6] == 0 &&   // 0x0004 = full name
756
0
    buf2[12*j + 7] == 4) {
757
0
  break;
758
0
      }
759
0
    }
760
0
    if (j >= nNames) {
761
0
      goto err3;
762
0
    }
763
0
    stringPlatform = (buf2[12*j] << 8) | buf2[12*j + 1];
764
    // stringEncoding = (buf2[12*j + 2] << 8) | buf2[12*j + 3];
765
0
    stringUnicode = stringPlatform == 0 || stringPlatform == 3;
766
0
    stringLength = (buf2[12*j + 8] << 8) | buf2[12*j + 9];
767
0
    stringOffset = nameTabOffset + stringsOffset +
768
0
                   ((buf2[12*j + 10] << 8) | buf2[12*j + 11]);
769
0
    gfree(buf2);
770
0
    if (stringOffset < 0 ||
771
0
  stringOffset + stringLength < 0 ||
772
0
  stringOffset + stringLength > fileLength) {
773
0
      goto err2;
774
0
    }
775
0
    buf2 = (Guchar *)gmalloc(stringLength);
776
0
    fseek(f, stringOffset, SEEK_SET);
777
0
    if ((int)fread(buf2, 1, stringLength, f) != stringLength) {
778
0
      goto err3;
779
0
    }
780
0
    if (stringUnicode) {
781
0
      stringLength /= 2;
782
0
      for (j = 0; j < stringLength; ++j) {
783
0
  buf2[j] = buf2[2*j + 1];
784
0
      }
785
0
    }
786
0
    ret->append(new GString((char *)buf2, stringLength));
787
0
    gfree(buf2);
788
0
  }
789
0
  return ret;
790
791
0
 err3:
792
0
  gfree(buf2);
793
0
 err2:
794
0
  deleteGList(ret, GString);
795
0
 err1:
796
0
  return NULL;
797
0
}
798
799
0
static GList *getDfontFontList(FILE *f) {
800
0
  Guchar buf[16];
801
0
  Guchar *resMap;
802
0
  int fileLength, resMapOffset, resMapLength;
803
0
  int resTypeListOffset, resNameListOffset, nTypes;
804
0
  int refListOffset, nFonts, nameOffset, nameLen;
805
0
  int offset, i;
806
0
  GList *ret;
807
808
0
  fseek(f, 0, SEEK_END);
809
0
  fileLength = (int)ftell(f);
810
0
  if (fileLength < 0) {
811
0
    goto err1;
812
0
  }
813
0
  fseek(f, 0, SEEK_SET);
814
0
  if (fread((char *)buf, 1, 16, f) != 16) {
815
0
    goto err1;
816
0
  }
817
0
  resMapOffset = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
818
0
  resMapLength = (buf[12] << 24) | (buf[13] << 16) | (buf[14] << 8) | buf[15];
819
0
  if (resMapOffset < 0 ||
820
0
      resMapOffset >= fileLength ||
821
0
      resMapLength < 0 ||
822
0
      resMapOffset + resMapLength > fileLength ||
823
0
      resMapOffset + resMapLength < 0) {
824
0
    goto err1;
825
0
  }
826
0
  if (resMapLength > 32768) {
827
    // sanity check - this probably isn't a dfont file
828
0
    goto err1;
829
0
  }
830
0
  resMap = (Guchar *)gmalloc(resMapLength);
831
0
  fseek(f, resMapOffset, SEEK_SET);
832
0
  if ((int)fread((char *)resMap, 1, resMapLength, f) != resMapLength) {
833
0
    goto err2;
834
0
  }
835
0
  resTypeListOffset = (resMap[24] << 8) | resMap[25];
836
0
  resNameListOffset = (resMap[26] << 8) | resMap[27];
837
0
  nTypes = ((resMap[28] << 8) | resMap[29]) + 1;
838
0
  if (resTypeListOffset + 2 + nTypes * 8 > resMapLength ||
839
0
      resNameListOffset >= resMapLength) {
840
0
    goto err2;
841
0
  }
842
0
  nFonts = 0;
843
0
  refListOffset = 0;
844
0
  for (i = 0; i < nTypes; ++i) {
845
0
    offset = resTypeListOffset + 2 + 8 * i;
846
0
    if (resMap[offset] == 0x73 &&    // 'sfnt'
847
0
  resMap[offset+1] == 0x66 &&
848
0
  resMap[offset+2] == 0x6e &&
849
0
  resMap[offset+3] == 0x74) {
850
0
      nFonts = ((resMap[offset+4] << 8) | resMap[offset+5]) + 1;
851
0
      refListOffset = (resMap[offset+6] << 8) | resMap[offset+7];
852
0
      break;
853
0
    }
854
0
  }
855
0
  if (i >= nTypes) {
856
0
    goto err2;
857
0
  }
858
0
  if (resTypeListOffset + refListOffset >= resMapLength ||
859
0
      resTypeListOffset + refListOffset + nFonts * 12 > resMapLength) {
860
0
    goto err2;
861
0
  }
862
0
  ret = new GList();
863
0
  for (i = 0; i < nFonts; ++i) {
864
0
    offset = resTypeListOffset + refListOffset + 12 * i;
865
0
    nameOffset = (resMap[offset+2] << 8) | resMap[offset+3];
866
0
    offset = resNameListOffset + nameOffset;
867
0
    if (offset >= resMapLength) {
868
0
      goto err3;
869
0
    }
870
0
    nameLen = resMap[offset];
871
0
    if (offset + 1 + nameLen > resMapLength) {
872
0
      goto err3;
873
0
    }
874
0
    ret->append(new GString((char *)resMap + offset + 1, nameLen));
875
0
  }
876
0
  gfree(resMap);
877
0
  return ret;
878
879
0
 err3:
880
0
  deleteGList(ret, GString);
881
0
 err2:
882
0
  gfree(resMap);
883
0
 err1:
884
  return NULL;
885
0
}