Coverage Report

Created: 2023-09-25 06:35

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