1//========================================================================
2//
3// FoFiIdentifier.cc
4//
5// Copyright 2009 Glyph & Cog, LLC
6//
7//========================================================================
8
9//========================================================================
10//
11// Modified under the Poppler project - http://poppler.freedesktop.org
12//
13// All changes made under the Poppler project to this file are licensed
14// under GPL version 2 or later
15//
16// Copyright (C) 2013 Christoph Duelli <duelli@melosgmbh.de>
17// Copyright (C) 2018, 2021 Albert Astals Cid <aacid@kde.org>
18// Copyright (C) 2019 Christian Persch <chpe@src.gnome.org>
19// Copyright (C) 2019 LE GARREC Vincent <legarrec.vincent@gmail.com>
20//
21// To see a description of the changes please see the Changelog file that
22// came with your tarball or type make ChangeLog if you are building from git
23//
24//========================================================================
25
26#include <cstdio>
27#include <cstring>
28#include <climits>
29#include "goo/gfile.h"
30#include "goo/GooCheckedOps.h"
31#include "FoFiIdentifier.h"
32
33//------------------------------------------------------------------------
34
35namespace { // do not pollute global namespace
36
37class Reader
38{
39public:
40 Reader() = default;
41 Reader(const Reader &) = delete;
42 Reader &operator=(const Reader &other) = delete;
43
44 virtual ~Reader() { }
45
46 // Read one byte. Returns -1 if past EOF.
47 virtual int getByte(int pos) = 0;
48
49 // Read a big-endian unsigned 16-bit integer. Fills in *val and
50 // returns true if successful.
51 virtual bool getU16BE(int pos, int *val) = 0;
52
53 // Read a big-endian unsigned 32-bit integer. Fills in *val and
54 // returns true if successful.
55 virtual bool getU32BE(int pos, unsigned int *val) = 0;
56
57 // Read a little-endian unsigned 32-bit integer. Fills in *val and
58 // returns true if successful.
59 virtual bool getU32LE(int pos, unsigned int *val) = 0;
60
61 // Read a big-endian unsigned <size>-byte integer, where 1 <= size
62 // <= 4. Fills in *val and returns true if successful.
63 virtual bool getUVarBE(int pos, int size, unsigned int *val) = 0;
64
65 // Compare against a string. Returns true if equal.
66 virtual bool cmp(int pos, const char *s) = 0;
67};
68
69//------------------------------------------------------------------------
70
71class MemReader : public Reader
72{
73public:
74 static MemReader *make(const char *bufA, int lenA);
75 ~MemReader() override;
76 int getByte(int pos) override;
77 bool getU16BE(int pos, int *val) override;
78 bool getU32BE(int pos, unsigned int *val) override;
79 bool getU32LE(int pos, unsigned int *val) override;
80 bool getUVarBE(int pos, int size, unsigned int *val) override;
81 bool cmp(int pos, const char *s) override;
82
83private:
84 MemReader(const char *bufA, int lenA);
85
86 const char *buf;
87 int len;
88};
89
90MemReader *MemReader::make(const char *bufA, int lenA)
91{
92 return new MemReader(bufA, lenA);
93}
94
95MemReader::MemReader(const char *bufA, int lenA)
96{
97 buf = bufA;
98 len = lenA;
99}
100
101MemReader::~MemReader() { }
102
103int MemReader::getByte(int pos)
104{
105 if (pos < 0 || pos >= len) {
106 return -1;
107 }
108 return buf[pos] & 0xff;
109}
110
111bool MemReader::getU16BE(int pos, int *val)
112{
113 if (pos < 0 || pos > len - 2) {
114 return false;
115 }
116 *val = ((buf[pos] & 0xff) << 8) + (buf[pos + 1] & 0xff);
117 return true;
118}
119
120bool MemReader::getU32BE(int pos, unsigned int *val)
121{
122 if (pos < 0 || pos > len - 4) {
123 return false;
124 }
125 *val = ((buf[pos] & 0xff) << 24) + ((buf[pos + 1] & 0xff) << 16) + ((buf[pos + 2] & 0xff) << 8) + (buf[pos + 3] & 0xff);
126 return true;
127}
128
129bool MemReader::getU32LE(int pos, unsigned int *val)
130{
131 if (pos < 0 || pos > len - 4) {
132 return false;
133 }
134 *val = (buf[pos] & 0xff) + ((buf[pos + 1] & 0xff) << 8) + ((buf[pos + 2] & 0xff) << 16) + ((buf[pos + 3] & 0xff) << 24);
135 return true;
136}
137
138bool MemReader::getUVarBE(int pos, int size, unsigned int *val)
139{
140 int i;
141
142 if (size < 1 || size > 4 || pos < 0 || pos > len - size) {
143 return false;
144 }
145 *val = 0;
146 for (i = 0; i < size; ++i) {
147 *val = (*val << 8) + (buf[pos + i] & 0xff);
148 }
149 return true;
150}
151
152bool MemReader::cmp(int pos, const char *s)
153{
154 int n;
155
156 n = (int)strlen(s: s);
157 if (pos < 0 || len < n || pos > len - n) {
158 return false;
159 }
160 return !memcmp(s1: buf + pos, s2: s, n: n);
161}
162
163//------------------------------------------------------------------------
164
165class FileReader : public Reader
166{
167public:
168 static FileReader *make(const char *fileName);
169 ~FileReader() override;
170 int getByte(int pos) override;
171 bool getU16BE(int pos, int *val) override;
172 bool getU32BE(int pos, unsigned int *val) override;
173 bool getU32LE(int pos, unsigned int *val) override;
174 bool getUVarBE(int pos, int size, unsigned int *val) override;
175 bool cmp(int pos, const char *s) override;
176
177private:
178 explicit FileReader(FILE *fA);
179 bool fillBuf(int pos, int len);
180
181 FILE *f;
182 char buf[1024];
183 int bufPos, bufLen;
184};
185
186FileReader *FileReader::make(const char *fileName)
187{
188 FILE *fA;
189
190 if (!(fA = openFile(path: fileName, mode: "rb"))) {
191 return nullptr;
192 }
193 return new FileReader(fA);
194}
195
196FileReader::FileReader(FILE *fA)
197{
198 f = fA;
199 bufPos = 0;
200 bufLen = 0;
201}
202
203FileReader::~FileReader()
204{
205 fclose(stream: f);
206}
207
208int FileReader::getByte(int pos)
209{
210 if (!fillBuf(pos, len: 1)) {
211 return -1;
212 }
213 return buf[pos - bufPos] & 0xff;
214}
215
216bool FileReader::getU16BE(int pos, int *val)
217{
218 if (!fillBuf(pos, len: 2)) {
219 return false;
220 }
221 *val = ((buf[pos - bufPos] & 0xff) << 8) + (buf[pos - bufPos + 1] & 0xff);
222 return true;
223}
224
225bool FileReader::getU32BE(int pos, unsigned int *val)
226{
227 if (!fillBuf(pos, len: 4)) {
228 return false;
229 }
230 *val = ((buf[pos - bufPos] & 0xff) << 24) + ((buf[pos - bufPos + 1] & 0xff) << 16) + ((buf[pos - bufPos + 2] & 0xff) << 8) + (buf[pos - bufPos + 3] & 0xff);
231 return true;
232}
233
234bool FileReader::getU32LE(int pos, unsigned int *val)
235{
236 if (!fillBuf(pos, len: 4)) {
237 return false;
238 }
239 *val = (buf[pos - bufPos] & 0xff) + ((buf[pos - bufPos + 1] & 0xff) << 8) + ((buf[pos - bufPos + 2] & 0xff) << 16) + ((buf[pos - bufPos + 3] & 0xff) << 24);
240 return true;
241}
242
243bool FileReader::getUVarBE(int pos, int size, unsigned int *val)
244{
245 int i;
246
247 if (size < 1 || size > 4 || !fillBuf(pos, len: size)) {
248 return false;
249 }
250 *val = 0;
251 for (i = 0; i < size; ++i) {
252 *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff);
253 }
254 return true;
255}
256
257bool FileReader::cmp(int pos, const char *s)
258{
259 int n;
260
261 n = (int)strlen(s: s);
262 if (!fillBuf(pos, len: n)) {
263 return false;
264 }
265 return !memcmp(s1: buf - bufPos + pos, s2: s, n: n);
266}
267
268bool FileReader::fillBuf(int pos, int len)
269{
270 if (pos < 0 || len < 0 || len > (int)sizeof(buf) || pos > INT_MAX - (int)sizeof(buf)) {
271 return false;
272 }
273 if (pos >= bufPos && pos + len <= bufPos + bufLen) {
274 return true;
275 }
276 if (fseek(stream: f, off: pos, SEEK_SET)) {
277 return false;
278 }
279 bufPos = pos;
280 bufLen = (int)fread(ptr: buf, size: 1, n: sizeof(buf), stream: f);
281 if (bufLen < len) {
282 return false;
283 }
284 return true;
285}
286
287//------------------------------------------------------------------------
288
289class StreamReader : public Reader
290{
291public:
292 static StreamReader *make(int (*getCharA)(void *data), void *dataA);
293 ~StreamReader() override;
294 int getByte(int pos) override;
295 bool getU16BE(int pos, int *val) override;
296 bool getU32BE(int pos, unsigned int *val) override;
297 bool getU32LE(int pos, unsigned int *val) override;
298 bool getUVarBE(int pos, int size, unsigned int *val) override;
299 bool cmp(int pos, const char *s) override;
300
301private:
302 StreamReader(int (*getCharA)(void *data), void *dataA);
303 bool fillBuf(int pos, int len);
304
305 int (*getChar)(void *data);
306 void *data;
307 int streamPos;
308 char buf[1024];
309 int bufPos, bufLen;
310};
311
312StreamReader *StreamReader::make(int (*getCharA)(void *data), void *dataA)
313{
314 return new StreamReader(getCharA, dataA);
315}
316
317StreamReader::StreamReader(int (*getCharA)(void *data), void *dataA)
318{
319 getChar = getCharA;
320 data = dataA;
321 streamPos = 0;
322 bufPos = 0;
323 bufLen = 0;
324}
325
326StreamReader::~StreamReader() { }
327
328int StreamReader::getByte(int pos)
329{
330 if (!fillBuf(pos, len: 1)) {
331 return -1;
332 }
333 return buf[pos - bufPos] & 0xff;
334}
335
336bool StreamReader::getU16BE(int pos, int *val)
337{
338 if (!fillBuf(pos, len: 2)) {
339 return false;
340 }
341 *val = ((buf[pos - bufPos] & 0xff) << 8) + (buf[pos - bufPos + 1] & 0xff);
342 return true;
343}
344
345bool StreamReader::getU32BE(int pos, unsigned int *val)
346{
347 if (!fillBuf(pos, len: 4)) {
348 return false;
349 }
350 *val = ((buf[pos - bufPos] & 0xff) << 24) + ((buf[pos - bufPos + 1] & 0xff) << 16) + ((buf[pos - bufPos + 2] & 0xff) << 8) + (buf[pos - bufPos + 3] & 0xff);
351 return true;
352}
353
354bool StreamReader::getU32LE(int pos, unsigned int *val)
355{
356 if (!fillBuf(pos, len: 4)) {
357 return false;
358 }
359 *val = (buf[pos - bufPos] & 0xff) + ((buf[pos - bufPos + 1] & 0xff) << 8) + ((buf[pos - bufPos + 2] & 0xff) << 16) + ((buf[pos - bufPos + 3] & 0xff) << 24);
360 return true;
361}
362
363bool StreamReader::getUVarBE(int pos, int size, unsigned int *val)
364{
365 int i;
366
367 if (size < 1 || size > 4 || !fillBuf(pos, len: size)) {
368 return false;
369 }
370 *val = 0;
371 for (i = 0; i < size; ++i) {
372 *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff);
373 }
374 return true;
375}
376
377bool StreamReader::cmp(int pos, const char *s)
378{
379 const int n = (int)strlen(s: s);
380 if (!fillBuf(pos, len: n)) {
381 return false;
382 }
383 const int posDiff = pos - bufPos;
384 return !memcmp(s1: buf + posDiff, s2: s, n: n);
385}
386
387bool StreamReader::fillBuf(int pos, int len)
388{
389 int c;
390
391 if (pos < 0 || len < 0 || len > (int)sizeof(buf) || pos > INT_MAX - (int)sizeof(buf)) {
392 return false;
393 }
394 if (pos < bufPos) {
395 return false;
396 }
397
398 // if requested region will not fit in the current buffer...
399 if (pos + len > bufPos + (int)sizeof(buf)) {
400
401 // if the start of the requested data is already in the buffer, move
402 // it to the start of the buffer
403 if (pos < bufPos + bufLen) {
404 bufLen -= pos - bufPos;
405 memmove(dest: buf, src: buf + (pos - bufPos), n: bufLen);
406 bufPos = pos;
407
408 // otherwise discard data from the
409 // stream until we get to the requested position
410 } else {
411 bufPos += bufLen;
412 bufLen = 0;
413 while (bufPos < pos) {
414 if ((c = (*getChar)(data)) < 0) {
415 return false;
416 }
417 ++bufPos;
418 }
419 }
420 }
421
422 // read the rest of the requested data
423 while (bufPos + bufLen < pos + len) {
424 if ((c = (*getChar)(data)) < 0) {
425 return false;
426 }
427 buf[bufLen++] = (char)c;
428 }
429
430 return true;
431}
432
433}
434
435//------------------------------------------------------------------------
436
437static FoFiIdentifierType identify(Reader *reader);
438static FoFiIdentifierType identifyOpenType(Reader *reader);
439static FoFiIdentifierType identifyCFF(Reader *reader, int start);
440
441FoFiIdentifierType FoFiIdentifier::identifyMem(const char *file, int len)
442{
443 MemReader *reader;
444 FoFiIdentifierType type;
445
446 if (!(reader = MemReader::make(bufA: file, lenA: len))) {
447 return fofiIdError;
448 }
449 type = identify(reader);
450 delete reader;
451 return type;
452}
453
454FoFiIdentifierType FoFiIdentifier::identifyFile(const char *fileName)
455{
456 FileReader *reader;
457 FoFiIdentifierType type;
458
459 if (!(reader = FileReader::make(fileName))) {
460 return fofiIdError;
461 }
462 type = identify(reader);
463 delete reader;
464 return type;
465}
466
467FoFiIdentifierType FoFiIdentifier::identifyStream(int (*getChar)(void *data), void *data)
468{
469 StreamReader *reader;
470 FoFiIdentifierType type;
471
472 if (!(reader = StreamReader::make(getCharA: getChar, dataA: data))) {
473 return fofiIdError;
474 }
475 type = identify(reader);
476 delete reader;
477 return type;
478}
479
480static FoFiIdentifierType identify(Reader *reader)
481{
482 unsigned int n;
483
484 //----- PFA
485 if (reader->cmp(pos: 0, s: "%!PS-AdobeFont-1") || reader->cmp(pos: 0, s: "%!FontType1")) {
486 return fofiIdType1PFA;
487 }
488
489 //----- PFB
490 if (reader->getByte(pos: 0) == 0x80 && reader->getByte(pos: 1) == 0x01 && reader->getU32LE(pos: 2, val: &n)) {
491 if ((n >= 16 && reader->cmp(pos: 6, s: "%!PS-AdobeFont-1")) || (n >= 11 && reader->cmp(pos: 6, s: "%!FontType1"))) {
492 return fofiIdType1PFB;
493 }
494 }
495
496 //----- TrueType
497 if ((reader->getByte(pos: 0) == 0x00 && reader->getByte(pos: 1) == 0x01 && reader->getByte(pos: 2) == 0x00 && reader->getByte(pos: 3) == 0x00)
498 || (reader->getByte(pos: 0) == 0x74 && // 'true'
499 reader->getByte(pos: 1) == 0x72 && reader->getByte(pos: 2) == 0x75 && reader->getByte(pos: 3) == 0x65)) {
500 return fofiIdTrueType;
501 }
502 if (reader->getByte(pos: 0) == 0x74 && // 'ttcf'
503 reader->getByte(pos: 1) == 0x74 && reader->getByte(pos: 2) == 0x63 && reader->getByte(pos: 3) == 0x66) {
504 return fofiIdTrueTypeCollection;
505 }
506
507 //----- OpenType
508 if (reader->getByte(pos: 0) == 0x4f && // 'OTTO
509 reader->getByte(pos: 1) == 0x54 && reader->getByte(pos: 2) == 0x54 && reader->getByte(pos: 3) == 0x4f) {
510 return identifyOpenType(reader);
511 }
512
513 //----- CFF
514 if (reader->getByte(pos: 0) == 0x01 && reader->getByte(pos: 1) == 0x00) {
515 return identifyCFF(reader, start: 0);
516 }
517 // some tools embed CFF fonts with an extra whitespace char at the
518 // beginning
519 if (reader->getByte(pos: 1) == 0x01 && reader->getByte(pos: 2) == 0x00) {
520 return identifyCFF(reader, start: 1);
521 }
522
523 return fofiIdUnknown;
524}
525
526static FoFiIdentifierType identifyOpenType(Reader *reader)
527{
528 FoFiIdentifierType type;
529 unsigned int offset;
530 int nTables, i;
531
532 if (!reader->getU16BE(pos: 4, val: &nTables)) {
533 return fofiIdUnknown;
534 }
535 for (i = 0; i < nTables; ++i) {
536 if (reader->cmp(pos: 12 + i * 16, s: "CFF ")) {
537 if (reader->getU32BE(pos: 12 + i * 16 + 8, val: &offset) && offset < (unsigned int)INT_MAX) {
538 type = identifyCFF(reader, start: (int)offset);
539 if (type == fofiIdCFF8Bit) {
540 type = fofiIdOpenTypeCFF8Bit;
541 } else if (type == fofiIdCFFCID) {
542 type = fofiIdOpenTypeCFFCID;
543 }
544 return type;
545 }
546 return fofiIdUnknown;
547 }
548 }
549 return fofiIdUnknown;
550}
551
552static FoFiIdentifierType identifyCFF(Reader *reader, int start)
553{
554 unsigned int offset0, offset1;
555 int hdrSize, offSize0, offSize1, pos, endPos, b0, n, i;
556
557 //----- read the header
558 if (reader->getByte(pos: start) != 0x01 || reader->getByte(pos: start + 1) != 0x00) {
559 return fofiIdUnknown;
560 }
561 if ((hdrSize = reader->getByte(pos: start + 2)) < 0) {
562 return fofiIdUnknown;
563 }
564 if ((offSize0 = reader->getByte(pos: start + 3)) < 1 || offSize0 > 4) {
565 return fofiIdUnknown;
566 }
567 pos = start + hdrSize;
568 if (pos < 0) {
569 return fofiIdUnknown;
570 }
571
572 //----- skip the name index
573 if (!reader->getU16BE(pos, val: &n)) {
574 return fofiIdUnknown;
575 }
576 if (n == 0) {
577 pos += 2;
578 } else {
579 if ((offSize1 = reader->getByte(pos: pos + 2)) < 1 || offSize1 > 4) {
580 return fofiIdUnknown;
581 }
582 if (!reader->getUVarBE(pos: pos + 3 + n * offSize1, size: offSize1, val: &offset1) || offset1 > (unsigned int)INT_MAX) {
583 return fofiIdUnknown;
584 }
585 pos += 3 + (n + 1) * offSize1 + (int)offset1 - 1;
586 }
587 if (pos < 0) {
588 return fofiIdUnknown;
589 }
590
591 //----- parse the top dict index
592 if (!reader->getU16BE(pos, val: &n) || n < 1) {
593 return fofiIdUnknown;
594 }
595 if ((offSize1 = reader->getByte(pos: pos + 2)) < 1 || offSize1 > 4) {
596 return fofiIdUnknown;
597 }
598 if (!reader->getUVarBE(pos: pos + 3, size: offSize1, val: &offset0) || offset0 > (unsigned int)INT_MAX || !reader->getUVarBE(pos: pos + 3 + offSize1, size: offSize1, val: &offset1) || offset1 > (unsigned int)INT_MAX || offset0 > offset1) {
599 return fofiIdUnknown;
600 }
601 if (checkedAdd(x: pos + 3 + (n + 1) * offSize1, y: (int)offset0 - 1, z: &pos) || checkedAdd(x: pos + 3 + (n + 1) * offSize1, y: (int)offset1 - 1, z: &endPos) || pos < 0 || endPos < 0 || pos > endPos) {
602 return fofiIdUnknown;
603 }
604
605 //----- parse the top dict, look for ROS as first entry
606 // for a CID font, the top dict starts with:
607 // <int> <int> <int> ROS
608 for (i = 0; i < 3; ++i) {
609 b0 = reader->getByte(pos: pos++);
610 if (b0 == 0x1c) {
611 pos += 2;
612 } else if (b0 == 0x1d) {
613 pos += 4;
614 } else if (b0 >= 0xf7 && b0 <= 0xfe) {
615 pos += 1;
616 } else if (b0 < 0x20 || b0 > 0xf6) {
617 return fofiIdCFF8Bit;
618 }
619 if (pos >= endPos || pos < 0) {
620 return fofiIdCFF8Bit;
621 }
622 }
623 if (pos + 1 < endPos && reader->getByte(pos) == 12 && reader->getByte(pos: pos + 1) == 30) {
624 return fofiIdCFFCID;
625 } else {
626 return fofiIdCFF8Bit;
627 }
628}
629

source code of poppler/fofi/FoFiIdentifier.cc