~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to filter/pdftopdf/P2PFont.cxx

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2012-07-28 11:54:32 UTC
  • mfrom: (1.1.17) (22 sid)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: package-import@ubuntu.com-20120728115432-p5fgn9hv6du22cqa
Tags: 1.0.20-1
* New upstream release
   - pdftops: Added another workaround for Kyocera printers: Some
     models get very slow on images which request interpolation,
     so now we remove the image interpolation requests by additional
     PostScript code only inserted for Kyocera printers (LP: #1026974).
   - Made the Poppler-based filters pdftopdf and pdftoopvp build with
     both Poppler 0.18.x and 0.20.x (Upstream bug #1055).
   - Fixes according to Coverity scan results (Upstream bug #1054).
   - Switched build system to autotools. This especially fixes several
     build problems in Gentoo. Also build-tested with CUPS 1.6.0b1.
   - Fixes for compatibility with clang/gcc-4.7.
   - textonly: Filter did not work as a pipe with copies=1 (Upstream bug
     #1032).
   - texttopdf: Avoid trimming the results of FcFontSort(), as this may
     miss some reasonable candidates under certain circumstances. BTW,
     fix passing a non-pointer as a pointer to "result" (Closes: #670055).
   - Corrected documentation. The option for the maximum image rendering
     resolution in pdftops is "pdftops-max-image-resolution", not
     "pdftops-max-image-resolution-default".
* debian/patches/fcfontsort-no-trim.patch: Removed, fixed upstream.
* debian/rules: Updated options for ./configure and make for the new autotools
  build system.
* debian/watch: Switched to bz2 upstream packages.
* debian/rules, debian/copyright, debian/cups-filters.docs: Updated for
  renamed documentation files.
* debian/control, debian/libfontembed1.install,
  debian/libfontembed-dev.install: Added new binary packages for libfontembed.
* debian/copyright: Updated for recent file additions, and rearrangement of
  directories.
* debian/control: Added missing build dependency on libpoppler-cpp-dev.
* debian/copyright: Corrections (Closes: #682752).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright (c) 2006-2007, BBR Inc.  All rights reserved.
 
4
 
 
5
Permission is hereby granted, free of charge, to any person obtaining
 
6
a copy of this software and associated documentation files (the
 
7
"Software"), to deal in the Software without restriction, including
 
8
without limitation the rights to use, copy, modify, merge, publish,
 
9
distribute, sublicense, and/or sell copies of the Software, and to
 
10
permit persons to whom the Software is furnished to do so, subject to
 
11
the following conditions:
 
12
 
 
13
The above copyright notice and this permission notice shall be included
 
14
in all copies or substantial portions of the Software.
 
15
 
 
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
17
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
18
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 
19
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 
20
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 
21
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 
22
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
23
 
 
24
*/
 
25
/*
 
26
 P2PFont.cc
 
27
 pdftopdf font manager
 
28
*/
 
29
 
 
30
#include <config.h>
 
31
#include <string.h>
 
32
#include <sys/types.h>
 
33
#include <unistd.h>
 
34
#include <fcntl.h>
 
35
#ifdef HAVE_CPP_POPPLER_VERSION_H
 
36
#include "cpp/poppler-version.h"
 
37
#endif
 
38
#include "goo/gmem.h"
 
39
#include "P2PFont.h"
 
40
#include "GfxFont.h"
 
41
#include "P2PError.h"
 
42
#include "P2PXRef.h"
 
43
#include "BuiltinFontTables.h"
 
44
#include "P2PCMap.h"
 
45
#include "GlobalParams.h"
 
46
#include "PDFFTrueTypeFont.h"
 
47
#include "P2PDoc.h"
 
48
#include "CharCodeToUnicode.h"
 
49
#include "P2PCharCodeToUnicode.h"
 
50
 
 
51
/* Size of CID (bytes) */
 
52
#define CID_SIZE 2
 
53
#define CIDTOGID_SIZE (1 << (8*CID_SIZE))
 
54
 
 
55
int P2PFontFile::nFontFiles = 0;
 
56
int P2PFontFile::fontFileListSize = 0;
 
57
P2PFontFile **P2PFontFile::fontFileList = 0;
 
58
char P2PFontFile::nextTag[7] = "AAAAA@";
 
59
 
 
60
#define FONT_FILE_LIST_INC 256
 
61
 
 
62
 
 
63
P2PCIDToGID::P2PCIDToGID(P2PFontFile *fontFileA, GBool wmodeA)
 
64
{
 
65
  fontFile = fontFileA;
 
66
  wmode = wmodeA;
 
67
}
 
68
 
 
69
P2PCIDToGID::~P2PCIDToGID()
 
70
{
 
71
  /* must not delete fontFile */
 
72
}
 
73
 
 
74
void P2PCIDToGID::output(P2POutputStream *str, XRef *xref)
 
75
{
 
76
  P2PObj *lenObj = new P2PObj();
 
77
  int cp;
 
78
  int len;
 
79
 
 
80
  P2PXRef::put(lenObj);
 
81
  outputBegin(str);
 
82
  str->puts("<< /Length ");
 
83
  lenObj->outputRef(str);
 
84
  if (P2PDoc::options.fontCompress && str->canDeflate()) {
 
85
    str->puts(" /Filter /FlateDecode ");
 
86
  }
 
87
  str->puts(" >>\n"
 
88
        "stream\n");
 
89
  cp = str->getPosition(); /* start position */
 
90
  if (P2PDoc::options.fontCompress) str->startDeflate();
 
91
  fontFile->outputCIDToGID(wmode,str,xref);
 
92
  if (P2PDoc::options.fontCompress) str->endDeflate();
 
93
  len = str->getPosition() - cp; /* calculate length */
 
94
  str->puts("\nendstream\n");
 
95
  outputEnd(str);
 
96
 
 
97
  /* output length */
 
98
  lenObj->outputBegin(str);
 
99
  str->printf("%d\n",len);
 
100
  lenObj->outputEnd(str);
 
101
}
 
102
 
 
103
char *P2PFontFile::getNextTag()
 
104
{
 
105
  int i;
 
106
 
 
107
  for (i = 5;i >= 0;i--) {
 
108
    int c = nextTag[i];
 
109
 
 
110
    nextTag[i] = ++c;
 
111
    if (c <= 'Z') break;
 
112
    nextTag[i] = 'A';
 
113
  }
 
114
  return nextTag;
 
115
}
 
116
 
 
117
P2PFontFile *P2PFontFile::getFontFile(GooString *fileNameA,
 
118
  GfxFont *fontA, GfxFontType typeA, int faceIndexA)
 
119
{
 
120
  int i;
 
121
 
 
122
  for (i = 0;i < nFontFiles;i++) {
 
123
    if (fontFileList[i] != 0 && strcmp(fileNameA->getCString(),
 
124
         fontFileList[i]->getFileName()->getCString()) == 0
 
125
         && faceIndexA == fontFileList[i]->faceIndex) {
 
126
      return fontFileList[i];
 
127
    }
 
128
  }
 
129
  if (nFontFiles >= fontFileListSize) {
 
130
    int size = fontFileListSize + FONT_FILE_LIST_INC;
 
131
    P2PFontFile **list;
 
132
 
 
133
    list = new P2PFontFile *[size];
 
134
    for (i = 0;i < nFontFiles;i++) {
 
135
      list[i] = fontFileList[i];
 
136
    }
 
137
    for (;i < size;i++) {
 
138
      list[i] = 0;
 
139
    }
 
140
    delete fontFileList;
 
141
    fontFileList = list;
 
142
    fontFileListSize = size;
 
143
  }
 
144
  fontFileList[nFontFiles] = new P2PFontFile(fileNameA,fontA,typeA,faceIndexA);
 
145
  P2PXRef::put(fontFileList[nFontFiles]);
 
146
  return fontFileList[nFontFiles++];
 
147
}
 
148
 
 
149
P2PFontFile::P2PFontFile(GooString *fileNameA, GfxFont *fontA,
 
150
  GfxFontType typeA, int faceIndexA)
 
151
{
 
152
  fileName = new GooString(fileNameA);
 
153
  font = fontA;
 
154
  type = typeA;
 
155
  faceIndex = faceIndexA;
 
156
  CIDToGID = 0;
 
157
  CIDToGID_V = 0;
 
158
  maxRefCID = 0;
 
159
  fontName = 0;
 
160
  setSecondPhase(gTrue);
 
161
  if (type == fontCIDType2) {
 
162
    charRefTable = new unsigned char[CIDTOGID_SIZE/8];
 
163
    memset(charRefTable,0,CIDTOGID_SIZE/8);
 
164
  } else {
 
165
    charRefTable = 0;
 
166
  }
 
167
  if (type == fontCIDType2 || type == fontTrueType) {
 
168
    UGooString *fn;
 
169
 
 
170
    tfont.init(fileName->getCString(),faceIndex);
 
171
    tfont.setupCmap();
 
172
    fn = tfont.getFontName();
 
173
    if (fn != 0) {
 
174
      if (type == fontCIDType2 && !P2PDoc::options.fontEmbeddingWhole) {
 
175
        char *tag;
 
176
        Unicode *p;
 
177
        int len;
 
178
        int tagLen;
 
179
        int fnLen;
 
180
        int i,j;
 
181
        Unicode *u;
 
182
 
 
183
        tag = getNextTag();
 
184
        tagLen = strlen(tag);
 
185
        fnLen = fn->getLength();
 
186
        len = tagLen+1+fnLen;
 
187
        /* use gmalloc because UGooString uses it */
 
188
        p = static_cast<Unicode *>(gmalloc(len*sizeof(Unicode)));
 
189
        /* copy tag */
 
190
        for (i = 0;i < tagLen;i++) {
 
191
          p[i] = tag[i];
 
192
        }
 
193
        p[i++] = '+';
 
194
        /* copy font name */
 
195
        u = fn->unicode();
 
196
        for (j = 0;j < fnLen;j++) {
 
197
          p[i++] = u[j];
 
198
        }
 
199
        fontName = new UGooString(p,len);
 
200
      } else {
 
201
        fontName = new UGooString(*fn);
 
202
      }
 
203
    }
 
204
  }
 
205
}
 
206
 
 
207
P2PCIDToGID *P2PFontFile::getCIDToGID(GBool wmode)
 
208
{
 
209
  P2PCIDToGID **p;
 
210
 
 
211
  if (wmode) {
 
212
    p = &CIDToGID_V;
 
213
  } else {
 
214
    p = &CIDToGID;
 
215
  }
 
216
  if (*p == 0) {
 
217
    *p = new P2PCIDToGID(this,wmode);
 
218
    P2PXRef::put(*p);
 
219
  }
 
220
  return *p;
 
221
}
 
222
 
 
223
P2PFontFile::~P2PFontFile()
 
224
{
 
225
  if (fileName != 0) {
 
226
    delete fileName;
 
227
  }
 
228
  if (charRefTable != 0) delete[] charRefTable;
 
229
  if (fontName != 0) delete fontName;
 
230
  /* font is deleted by P2PFontDict, you must not delete it here */
 
231
  /* must not delete CIDToGID */
 
232
}
 
233
 
 
234
GBool P2PFontFile::isIdentity()
 
235
{
 
236
  /* alway false now */
 
237
  return gFalse;
 
238
}
 
239
 
 
240
void P2PFontFile::outputCIDToGID(GBool wmode, P2POutputStream *str, XRef *xref)
 
241
{
 
242
#define N_UCS_CANDIDATES 2
 
243
  /* space characters */
 
244
  static unsigned long spaces[] = {
 
245
    0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007,
 
246
    0x2008,0x2009,0x200A,0x00A0,0x200B,0x2060,0x3000,0xFEFF,
 
247
    0
 
248
  };
 
249
  static const char *adobe_cns1_cmaps[] = {
 
250
    "UniCNS-UTF32-V",
 
251
    "UniCNS-UCS2-V",
 
252
    "UniCNS-UTF32-H",
 
253
    "UniCNS-UCS2-H",
 
254
    0
 
255
  };
 
256
  static const char *adobe_gb1_cmaps[] = {
 
257
    "UniGB-UTF32-V",
 
258
    "UniGB-UCS2-V",
 
259
    "UniGB-UTF32-H",
 
260
    "UniGB-UCS2-H",
 
261
    0
 
262
  };
 
263
  static const char *adobe_japan1_cmaps[] = {
 
264
    "UniJIS-UTF32-V",
 
265
    "UniJIS-UCS2-V",
 
266
    "UniJIS-UTF32-H",
 
267
    "UniJIS-UCS2-H",
 
268
    0
 
269
  };
 
270
  static const char *adobe_japan2_cmaps[] = {
 
271
    "UniHojo-UTF32-V",
 
272
    "UniHojo-UCS2-V",
 
273
    "UniHojo-UTF32-H",
 
274
    "UniHojo-UCS2-H",
 
275
    0
 
276
  };
 
277
  static const char *adobe_korea1_cmaps[] = {
 
278
    "UniKS-UTF32-V",
 
279
    "UniKS-UCS2-V",
 
280
    "UniKS-UTF32-H",
 
281
    "UniKS-UCS2-H",
 
282
    0
 
283
  };
 
284
  static struct CMapListEntry {
 
285
    const char *collection;
 
286
    const char *scriptTag;
 
287
    const char *toUnicodeMap;
 
288
    const char **CMaps;
 
289
  } CMapList[] = {
 
290
    {
 
291
      "Adobe-CNS1",
 
292
      "kana",
 
293
      "Adobe-CNS1-UCS2",
 
294
      adobe_cns1_cmaps,
 
295
    },
 
296
    {
 
297
      "Adobe-GB1",
 
298
      "kana",
 
299
      "Adobe-GB1-UCS2",
 
300
      adobe_gb1_cmaps,
 
301
    },
 
302
    {
 
303
      "Adobe-Japan1",
 
304
      "kana",
 
305
      "Adobe-Japan1-UCS2",
 
306
      adobe_japan1_cmaps,
 
307
    },
 
308
    {
 
309
      "Adobe-Japan2",
 
310
      "kana",
 
311
      "Adobe-Japan2-UCS2",
 
312
      adobe_japan2_cmaps,
 
313
    },
 
314
    {
 
315
      "Adobe-Korea1",
 
316
      "kana",
 
317
      "Adobe-Korea1-UCS2",
 
318
      adobe_korea1_cmaps,
 
319
    },
 
320
    {
 
321
      0
 
322
    }
 
323
  };
 
324
  unsigned int i;
 
325
  Unicode *humap = 0;
 
326
  Unicode *vumap = 0;
 
327
  Unicode *tumap = 0;
 
328
 
 
329
  if (charRefTable == 0 || maxRefCID == 0) {
 
330
    str->putchar(0);
 
331
    str->putchar(0);
 
332
    return;
 
333
  }
 
334
  tfont.setupGSUB(0); /* reset GSUB */
 
335
  if (font != 0) {
 
336
    const char **cmapName;
 
337
    P2PCMap *cMap;
 
338
    CMapListEntry *lp;
 
339
    CharCodeToUnicode *octu;
 
340
 
 
341
    GfxCIDFont *cidfont = static_cast<GfxCIDFont *>(font);
 
342
    for (lp = CMapList;lp->collection != 0;lp++) {
 
343
      if (strcmp(lp->collection,cidfont->getCollection()->getCString()) == 0) {
 
344
        break;
 
345
      }
 
346
    }
 
347
    tumap = new Unicode[maxRefCID+1];
 
348
    if (lp->collection != 0) {
 
349
      GooString tname(lp->toUnicodeMap);
 
350
      P2PCharCodeToUnicode *ctu;
 
351
      if ((ctu = P2PCharCodeToUnicode::parseCMapFromFile(&tname,16)) != 0) {
 
352
        CharCode cid;
 
353
        for (cid = 0;cid <= maxRefCID ;cid++) {
 
354
          int len;
 
355
          Unicode ucodes[4];
 
356
 
 
357
          len = ctu->mapToUnicode(cid,ucodes,4);
 
358
          if (len == 1) {
 
359
            tumap[cid] = ucodes[0];
 
360
          } else {
 
361
            /* if not single character, ignore it */
 
362
            tumap[cid] = 0;
 
363
          }
 
364
        }
 
365
        delete ctu;
 
366
      }
 
367
      vumap = new Unicode[maxRefCID+1];
 
368
      memset(vumap,0,sizeof(Unicode)*(maxRefCID+1));
 
369
      humap = new Unicode[(maxRefCID+1)*N_UCS_CANDIDATES];
 
370
      memset(humap,0,sizeof(Unicode)*(maxRefCID+1)*N_UCS_CANDIDATES);
 
371
      for (cmapName = lp->CMaps;*cmapName != 0;cmapName++) {
 
372
        GooString cname(*cmapName);
 
373
 
 
374
        if ((cMap = P2PCMap::parse(&cmapCache,cidfont->getCollection(),&cname))
 
375
             != 0) {
 
376
          if (cMap->getWMode()) {
 
377
            cMap->setReverseMap(vumap,maxRefCID+1,1);
 
378
          } else {
 
379
            cMap->setReverseMap(humap,maxRefCID+1,N_UCS_CANDIDATES);
 
380
          }
 
381
          cMap->decRefCnt();
 
382
        }
 
383
      }
 
384
      tfont.setupGSUB(lp->scriptTag);
 
385
    } else {
 
386
      p2pError(-1,const_cast<char *>("Unknown character collection %s\n"),
 
387
        cidfont->getCollection()->getCString());
 
388
      if ((octu = cidfont->getToUnicode()) != 0) {
 
389
        CharCode cid;
 
390
        for (cid = 0;cid <= maxRefCID ;cid++) {
 
391
#ifdef OLD_MAPTOUNICODE
 
392
          Unicode ucode;
 
393
 
 
394
          humap[cid*N_UCS_CANDIDATES] = ucode;
 
395
#else
 
396
          Unicode *ucode = NULL;
 
397
 
 
398
          humap[cid*N_UCS_CANDIDATES] = *ucode;
 
399
#endif
 
400
          for (i = 1;i < N_UCS_CANDIDATES;i++) {
 
401
            humap[cid*N_UCS_CANDIDATES+i] = 0;
 
402
          }
 
403
        }
 
404
        octu->decRefCnt();
 
405
      }
 
406
    }
 
407
  }
 
408
  for (i = 0;i <= maxRefCID;i++) {
 
409
    Unicode unicode;
 
410
    unsigned long gid;
 
411
    int j;
 
412
 
 
413
    if ((charRefTable[i/8] & (1 << (i & (8-1)))) == 0) {
 
414
      /* not referenced CID */
 
415
      gid = 0;
 
416
    } else {
 
417
      /* referenced CID */
 
418
      unicode = 0;
 
419
      gid = 0;
 
420
      if (humap != 0) {
 
421
        for (j = 0;j < N_UCS_CANDIDATES
 
422
          && gid == 0 && (unicode = humap[i*N_UCS_CANDIDATES+j]) != 0;j++) {
 
423
          gid = tfont.getGID(unicode,gFalse,
 
424
            P2PDoc::options.fontEmbeddingWhole ? 1 : 0);
 
425
        }
 
426
      }
 
427
      if (gid == 0 && vumap != 0) {
 
428
        unicode = vumap[i];
 
429
        if (unicode != 0) {
 
430
          gid = tfont.getGID(unicode,gTrue,
 
431
            P2PDoc::options.fontEmbeddingWhole ? 1 : 0);
 
432
          if (gid == 0 && tumap != 0) {
 
433
            if ((unicode = tumap[i]) != 0) {
 
434
              gid = tfont.getGID(unicode,gTrue,
 
435
                P2PDoc::options.fontEmbeddingWhole ? 1 : 0);
 
436
            }
 
437
          }
 
438
        }
 
439
      }
 
440
      if (gid == 0 && tumap != 0) {
 
441
        if ((unicode = tumap[i]) != 0) {
 
442
            gid = tfont.getGID(unicode,gFalse,
 
443
              P2PDoc::options.fontEmbeddingWhole ? 1 : 0);
 
444
        }
 
445
      }
 
446
      if (gid == 0) {
 
447
        /* special handling space characters */
 
448
        unsigned long *p;
 
449
 
 
450
        if (humap != 0) unicode = humap[i];
 
451
        if (unicode != 0) {
 
452
          /* check if code is space character , so map code to 0x0020 */
 
453
          for (p = spaces;*p != 0;p++) {
 
454
            if (*p == unicode) {
 
455
              unicode = 0x20;
 
456
              gid = tfont.getGID(unicode,wmode,
 
457
                        P2PDoc::options.fontEmbeddingWhole ? 1 : 0);
 
458
              break;
 
459
            }
 
460
          }
 
461
        }
 
462
      }
 
463
    }
 
464
    /* output GID 
 
465
       size is 16bits.
 
466
       should output big endian format.
 
467
   */
 
468
    str->putchar((gid >> 8) & 0xff);
 
469
    str->putchar(gid & 0xff);
 
470
  }
 
471
  if (humap != 0) delete[] humap;
 
472
  if (vumap != 0) delete[] vumap;
 
473
}
 
474
 
 
475
void P2PFontFile::output(P2POutputStream *str, XRef *xref)
 
476
{
 
477
  int fd;
 
478
  char buf[BUFSIZ];
 
479
  int n;
 
480
  P2PObj *lenObj = new P2PObj();
 
481
  P2PObj *len1Obj = 0;
 
482
  int cp;
 
483
  int len,len1 = 0;
 
484
 
 
485
//  fprintf(stderr,"INFO:Embedding font file from file %s\n",
 
486
//   fileName->getCString());
 
487
  outputBegin(str);
 
488
  /* output stream dictionary */
 
489
  str->puts("<< ");
 
490
  switch (type) {
 
491
  case fontType1C:
 
492
    str->puts("/SubType /Type1C ");
 
493
    /* should output Length1, Length2, Length3 */
 
494
    break;
 
495
  case fontCIDType0C:
 
496
    str->puts("/SubType /CIDFontType0C ");
 
497
    /* should output Length1, Length2, Length3 */
 
498
    break;
 
499
  case fontTrueType:
 
500
  case fontCIDType2:
 
501
    len1Obj = new P2PObj();
 
502
    P2PXRef::put(len1Obj);
 
503
    str->puts("/Length1 ");
 
504
    len1Obj->outputRef(str);
 
505
    break;
 
506
  case fontType1:
 
507
  case fontCIDType0:
 
508
    /* should output Length1, Length2, Length3 */
 
509
    break;
 
510
  default:
 
511
    break;
 
512
  }
 
513
  P2PXRef::put(lenObj);
 
514
  str->puts("/Length ");
 
515
  lenObj->outputRef(str);
 
516
  if (P2PDoc::options.fontCompress && str->canDeflate()) {
 
517
    str->puts(" /Filter /FlateDecode ");
 
518
  }
 
519
  str->puts(" >>\n");
 
520
 
 
521
  /* output stream body */
 
522
  str->puts("stream\n");
 
523
  if (P2PDoc::options.fontCompress) str->startDeflate();
 
524
  cp = str->getPosition();
 
525
  switch (type) {
 
526
  case fontCIDType2:
 
527
    tfont.output(str);
 
528
    len1 = tfont.getLength();
 
529
    break;
 
530
  case fontType1:
 
531
  case fontCIDType0:
 
532
  case fontType1C:
 
533
  case fontCIDType0C:
 
534
  case fontTrueType:
 
535
  default:
 
536
    if ((fd = open(fileName->getCString(),O_RDONLY)) < 0) {
 
537
      p2pError(-1,const_cast<char *>("Cannot open FontFile:%s\n"),fileName->getCString());
 
538
      return;
 
539
    }
 
540
    while ((n = read(fd,buf,BUFSIZ)) > 0) {
 
541
      char *p = buf;
 
542
      int r;
 
543
 
 
544
      while (n > 0) {
 
545
        r = str->write(p,n);
 
546
        if (r <= 0) break;
 
547
        n -= r;
 
548
        p += r;
 
549
      }
 
550
    }
 
551
    close(fd);
 
552
    break;
 
553
  }
 
554
 
 
555
  if (P2PDoc::options.fontCompress) str->endDeflate();
 
556
  len = str->getPosition()-cp; /* calculate length */
 
557
  str->puts("\nendstream\n");
 
558
 
 
559
  outputEnd(str);
 
560
 
 
561
  /* output length */
 
562
  lenObj->outputBegin(str);
 
563
  str->printf("%d\n",len);
 
564
  lenObj->outputEnd(str);
 
565
 
 
566
  if (len1Obj != 0) {
 
567
    /* output length1 */
 
568
    len1Obj->outputBegin(str);
 
569
    str->printf("%d\n",len1);
 
570
    len1Obj->outputEnd(str);
 
571
  }
 
572
}
 
573
 
 
574
P2PFontDescriptor::P2PFontDescriptor(Object *descriptorA,
 
575
  GfxFont *fontA, GooString *fileName, GfxFontType typeA,
 
576
  int faceIndexA, XRef *xref, int num, int gen) : P2PObject(num,gen)
 
577
{
 
578
  descriptorA->copy(&descriptor);
 
579
  fontFile = P2PFontFile::getFontFile(fileName,fontA,typeA,faceIndexA);
 
580
  type = typeA;
 
581
}
 
582
 
 
583
P2PFontDescriptor::~P2PFontDescriptor()
 
584
{
 
585
  /* fontFile is pointed by multiple FontDescriptor,
 
586
     so, don't delete it here.  it is deleted by P2PXRef::clean() */
 
587
 
 
588
  descriptor.free();
 
589
}
 
590
 
 
591
void P2PFontDescriptor::output(P2POutputStream *str, XRef *xref)
 
592
{
 
593
  P2PObject *objs[2];
 
594
  const char *keys[2];
 
595
  int objsIndex = 0;
 
596
  P2PObj fnobj;
 
597
 
 
598
  /* only indirect referenced */
 
599
  outputBegin(str);
 
600
  if (fontFile != 0) {
 
601
    UGooString *fn;
 
602
 
 
603
    switch (type) {
 
604
    case fontCIDType0:
 
605
    case fontType1:
 
606
    default:
 
607
      keys[objsIndex] = "FontFile";
 
608
      break;
 
609
    case fontCIDType2:
 
610
    case fontTrueType:
 
611
      keys[objsIndex] = "FontFile2";
 
612
      break;
 
613
    case fontType1C:
 
614
    case fontCIDType0C:
 
615
      keys[objsIndex] = "FontFile3";
 
616
      break;
 
617
    }
 
618
    objs[objsIndex++] = fontFile;
 
619
    fn = fontFile->getFontName();
 
620
    if (fn != 0) {
 
621
      char *p;
 
622
 
 
623
      p = fn->getCString();
 
624
      fnobj.getObj()->initName(p);
 
625
      keys[objsIndex] = "FontName";
 
626
      objs[objsIndex++] = &fnobj;
 
627
      delete[] p;
 
628
    }
 
629
  }
 
630
  P2POutput::outputDict(descriptor.getDict(),keys,objs,objsIndex,str,xref);
 
631
  str->putchar('\n');
 
632
  outputEnd(str);
 
633
}
 
634
 
 
635
P2PCIDFontDict::P2PCIDFontDict(Object *fontDictA, GfxFont *fontA,
 
636
  GfxFontType typeA, GfxFontType embeddedTypeA,
 
637
  P2PFontDescriptor *fontDescriptorA, int num, int gen) : P2PObject(num,gen)
 
638
{
 
639
  type = typeA;
 
640
  embeddedType = embeddedTypeA;
 
641
  fontDictA->copy(&fontDict);
 
642
  fontDescriptor = fontDescriptorA;
 
643
  font = fontA;
 
644
}
 
645
 
 
646
P2PCIDFontDict::~P2PCIDFontDict()
 
647
{
 
648
  fontDict.free();
 
649
  /* must not delete font, it is deleted by P2PFontDict::~P2PFonrDict(). */
 
650
}
 
651
 
 
652
void P2PCIDFontDict::output(P2POutputStream *str, XRef *xref)
 
653
{
 
654
  P2PObject *objs[3];
 
655
  const char *keys[3];
 
656
  int objsIndex = 0;
 
657
  P2PObj *subtypeObjp = 0;
 
658
  P2PObj fnobj;
 
659
 
 
660
  if (embeddedType != type) {
 
661
    /* change subtype */
 
662
 
 
663
    subtypeObjp = new P2PObj();
 
664
    switch (embeddedType) {
 
665
    case fontCIDType0:
 
666
      subtypeObjp->getObj()->initName(const_cast<char *>("CIDFontType0"));
 
667
      break;
 
668
    case fontCIDType2:
 
669
      subtypeObjp->getObj()->initName(const_cast<char *>("CIDFontType2"));
 
670
      break;
 
671
    case fontTrueType:
 
672
    case fontUnknownType:
 
673
    case fontType1:
 
674
    case fontType1C:
 
675
    case fontType3:
 
676
    case fontCIDType0C:
 
677
    default:
 
678
      p2pError(-1,const_cast<char *>("P2PCIDFontDict: Illegal embedded font type"));
 
679
      goto end_output;
 
680
      break;
 
681
    }
 
682
    keys[objsIndex] = "Subtype";
 
683
    objs[objsIndex++] = subtypeObjp;
 
684
  }
 
685
  if (embeddedType == fontCIDType2) {
 
686
    /* Add CIDToGIDMap */
 
687
    P2PObject *objp;
 
688
    P2PFontFile *fontFile;
 
689
 
 
690
    fontFile = fontDescriptor->getFontFile();
 
691
    if (fontFile != 0) {
 
692
      UGooString *fn;
 
693
 
 
694
      if (!(fontFile->isIdentity())) {
 
695
        keys[objsIndex] = "CIDToGIDMap";
 
696
        objp = fontFile->getCIDToGID(font->getWMode());
 
697
        objs[objsIndex++] = objp;
 
698
      }
 
699
      fn = fontFile->getFontName();
 
700
      if (fn != 0) {
 
701
        char *p = fn->getCString();
 
702
        fnobj.getObj()->initName(p);
 
703
        keys[objsIndex] = "BaseFont";
 
704
        objs[objsIndex++] = &fnobj;
 
705
        delete[] p;
 
706
      }
 
707
    }
 
708
  }
 
709
 
 
710
  outputBegin(str);
 
711
  P2POutput::outputDict(fontDict.getDict(),keys,objs,objsIndex,str,xref);
 
712
  str->putchar('\n');
 
713
  outputEnd(str);
 
714
end_output:
 
715
  if (subtypeObjp != 0) {
 
716
    delete subtypeObjp;
 
717
  }
 
718
}
 
719
 
 
720
P2PDescendantFontsWrapper::P2PDescendantFontsWrapper(P2PObject *elementA)
 
721
{
 
722
  element = elementA;
 
723
}
 
724
 
 
725
P2PDescendantFontsWrapper::~P2PDescendantFontsWrapper()
 
726
{
 
727
  /* do nothing */
 
728
}
 
729
 
 
730
void P2PDescendantFontsWrapper::output(P2POutputStream *str, XRef *xref)
 
731
{
 
732
  str->puts("[ ");
 
733
  element->outputRef(str);
 
734
  str->puts(" ]");
 
735
}
 
736
 
 
737
void P2PFontDict::doReadFontDescriptor(Object *dictObj,
 
738
  GfxFontType type, const char *name, XRef *xref)
 
739
{
 
740
  Dict *dict = dictObj->getDict();
 
741
  Object obj;
 
742
  int num, gen;
 
743
  P2PObject *p;
 
744
  int faceIndex = 0;
 
745
 
 
746
  if (dict->lookupNF(const_cast<char *>("FontDescriptor"),&obj) == 0
 
747
       || obj.isNull()) {
 
748
    /* no FontDescriptor */
 
749
    p2pError(-1,const_cast<char *>("Font:%s has no FontDescriptor entry.\n"),name);
 
750
    return;
 
751
  }
 
752
  if (!obj.isRef()) {
 
753
    /* not indirect reference is error */
 
754
    p2pError(-1,const_cast<char *>("FontDescriptor entry of Font:%s is not indirect.\n"),name);
 
755
    goto end_read;
 
756
  }
 
757
  num = obj.getRefNum();
 
758
  gen = obj.getRefGen();
 
759
  if ((p = P2PObject::find(num,gen)) != 0) {
 
760
    /* already read */
 
761
    fontDescriptor = static_cast<P2PFontDescriptor *>(p);
 
762
    embeddedType = fontDescriptor->getType();
 
763
  } else {
 
764
    P2PFontFile *fp;
 
765
    UGooString *ugs;
 
766
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
767
    GooString *fileName;
 
768
 
 
769
    SysFontType sftype;
 
770
    fileName = globalParams->findSystemFontFile(font,&sftype,
 
771
        &faceIndex, NULL);
 
772
    if (fileName == 0) {
 
773
      p2pError(-1, const_cast<char *>("Couldn't find a font for %s. Not embedded\n"),name);
 
774
      goto end_read;
 
775
    }
 
776
    switch (sftype) {
 
777
    case sysFontPFA:
 
778
    case sysFontPFB:
 
779
      p2pError(-1, const_cast<char *>("Found a Type1 font for font:%s. Embedding Type1 font not supported yet."),name);
 
780
      goto end_read;
 
781
      break;
 
782
    case sysFontTTF:
 
783
    case sysFontTTC:
 
784
      switch (type) {
 
785
      case fontCIDType2:
 
786
      case fontTrueType:
 
787
        break;
 
788
      case fontCIDType0C:
 
789
      case fontCIDType0:
 
790
        embeddedType = fontCIDType2;
 
791
        break;
 
792
      case fontType1:
 
793
      case fontType1C:
 
794
        embeddedType = fontTrueType;
 
795
        break;
 
796
      default:
 
797
        p2pError(-1, const_cast<char *>("Illegal type font\n"));
 
798
        goto end_read;
 
799
      }
 
800
      break;
 
801
    default:
 
802
      p2pError(-1, const_cast<char *>("found a unknown type font for %s. Not embedded\n"),name);
 
803
      goto end_read;
 
804
      break;
 
805
    }
 
806
#else
 
807
    GooString *fileName = font->getExtFontFile();
 
808
 
 
809
    if (fileName == 0) {
 
810
      DisplayFontParam *dfp = 0;
 
811
      /* look for substitute font */
 
812
 
 
813
      if (font->getName()) {
 
814
        dfp = globalParams->getDisplayFont(font);
 
815
        /* a caller must not delete dfp */
 
816
      }
 
817
      if (dfp == 0) {
 
818
        p2pError(-1, const_cast<char *>("Couldn't find a font for %s. Not embedded\n"),name);
 
819
        goto end_read;
 
820
      }
 
821
      switch (dfp->kind) {
 
822
      case displayFontT1:
 
823
        p2pError(-1, const_cast<char *>("Found a Type1 font for font:%s. Embedding Type1 font not supported yet."),name);
 
824
        goto end_read;
 
825
        break;
 
826
      case displayFontTT:
 
827
        switch (type) {
 
828
        case fontCIDType2:
 
829
        case fontTrueType:
 
830
          break;
 
831
        case fontCIDType0C:
 
832
        case fontCIDType0:
 
833
          embeddedType = fontCIDType2;
 
834
          break;
 
835
        case fontType1:
 
836
        case fontType1C:
 
837
          embeddedType = fontTrueType;
 
838
          break;
 
839
        default:
 
840
          p2pError(-1, const_cast<char *>("Illegal type font\n"));
 
841
          goto end_read;
 
842
        }
 
843
        fileName = dfp->tt.fileName;
 
844
        faceIndex = dfp->tt.faceIndex;
 
845
        break;
 
846
      default:
 
847
        p2pError(-1, const_cast<char *>("found a unknown type font for %s. Not embedded\n"),name);
 
848
        goto end_read;
 
849
        break;
 
850
      }
 
851
    }
 
852
#endif
 
853
    /* reset obj */
 
854
    obj.free();
 
855
 
 
856
    xref->fetch(num,gen,&obj);
 
857
    if (!obj.isDict()) {
 
858
        p2pError(-1, const_cast<char *>("Font Descriptor of Font:%s is not Dictionary. Not embedded\n"),name);
 
859
        goto end_read;
 
860
    }
 
861
//fprintf(stderr, "DEBUG: Embedding Font fileName=%s for %s\n",fileName->getCString(),name);
 
862
    fontDescriptor = new P2PFontDescriptor(&obj,font,fileName,
 
863
      embeddedType, faceIndex, xref,num,gen);
 
864
    P2PXRef::put(fontDescriptor);
 
865
    fp = fontDescriptor->getFontFile();
 
866
    ugs = 0;
 
867
    if (fp != 0) {
 
868
      ugs = fp->getFontName();
 
869
      if (ugs != 0) {
 
870
        char *cs = ugs->getCString();
 
871
 
 
872
        fprintf(stderr, "INFO: Embedded Font=%s, from fileName=%s for %s\n",
 
873
          cs,fileName->getCString(),name);
 
874
        delete[] cs;
 
875
      }
 
876
    }
 
877
    if (ugs == 0) {
 
878
      fprintf(stderr, "INFO: Embedded Font from fileName=%s for %s\n",
 
879
        fileName->getCString(),name);
 
880
    }
 
881
  }
 
882
end_read:
 
883
  obj.free();
 
884
}
 
885
 
 
886
void P2PFontDict::read8bitFontDescriptor(GfxFontType type, const char *name,
 
887
  XRef *xref)
 
888
{
 
889
  doReadFontDescriptor(&fontDict,type,name,xref);
 
890
}
 
891
 
 
892
void P2PFontDict::readCIDFontDescriptor(GfxFontType type, const char *name,
 
893
  XRef *xref)
 
894
{
 
895
  Object obj;
 
896
  Object descendant;
 
897
  Dict *dict = fontDict.getDict();
 
898
  int num = -1, gen = -1;
 
899
 
 
900
  if (dict->lookup(const_cast<char *>("DescendantFonts"),&obj) == 0
 
901
       || obj.isNull()) {
 
902
    /* no DescendantFonts */
 
903
    p2pError(-1,const_cast<char *>("Font:%s has no DescendantFonts entry.\n"),name);
 
904
    return;
 
905
  }
 
906
  if (!obj.isArray() || obj.arrayGetNF(0,&descendant) == 0) {
 
907
    /* illegal DescendantFonts */
 
908
    p2pError(-1,const_cast<char *>("Font:%s has illegal DescendantFonts entry.\n"),name);
 
909
    goto end_read;
 
910
  }
 
911
  if (descendant.isRef()) {
 
912
    num = descendant.getRefNum();
 
913
    gen = descendant.getRefGen();
 
914
 
 
915
    cidFontDict = static_cast<P2PCIDFontDict *>(
 
916
      P2PObject::find(num,gen));
 
917
    if (cidFontDict == 0) {
 
918
      /* reset obj */
 
919
      descendant.free();
 
920
      xref->fetch(num,gen,&descendant);
 
921
    }
 
922
  }
 
923
  if (cidFontDict == 0) {
 
924
    if (!descendant.isDict()) {
 
925
      p2pError(-1,const_cast<char *>("Font:%s has illegal DescendantFonts entry.\n"),name);
 
926
      goto end_read1;
 
927
    }
 
928
    doReadFontDescriptor(&descendant,type,name,xref);
 
929
    cidFontDict = new P2PCIDFontDict(&descendant,font,type,
 
930
      embeddedType,fontDescriptor,num,gen);
 
931
    if (num > 0) P2PXRef::put(cidFontDict);
 
932
  }
 
933
end_read1:
 
934
  descendant.free();
 
935
end_read:
 
936
  obj.free();
 
937
}
 
938
 
 
939
UGooString *P2PFontDict::getEmbeddingFontName()
 
940
{
 
941
  P2PFontDescriptor *desc = fontDescriptor;
 
942
 
 
943
  if (cidFontDict != 0) {
 
944
    desc = cidFontDict->getFontDescriptor();
 
945
  }
 
946
  if (desc != 0) {
 
947
    P2PFontFile *file = desc->getFontFile();
 
948
    if (file != 0) return file->getFontName();
 
949
  }
 
950
  return 0;
 
951
}
 
952
 
 
953
void P2PFontDict::output(P2POutputStream *str, XRef *xref)
 
954
{
 
955
  int num, gen;
 
956
  P2PObject *objs[2];
 
957
  const char *keys[2];
 
958
  int nobjs = 0;
 
959
  UGooString *fn;
 
960
  P2PObj fnobj;
 
961
 
 
962
  fn = getEmbeddingFontName();
 
963
  if (fn != 0) {
 
964
    keys[nobjs] = "BaseFont";
 
965
    char *p = fn->getCString();
 
966
    fnobj.getObj()->initName(p);
 
967
    objs[nobjs] = &fnobj;
 
968
    nobjs++;
 
969
    delete[] p;
 
970
  }
 
971
  /* output indirect referenced dictionary only */
 
972
  outputBegin(str);
 
973
  if (cidFontDict != 0) {
 
974
    cidFontDict->getNum(&num,&gen);
 
975
    if (num < 0) {
 
976
      /* not indirect referenced, change it indirect referenced */
 
977
      P2PDescendantFontsWrapper *wrap
 
978
         = new P2PDescendantFontsWrapper(cidFontDict);
 
979
      keys[nobjs] = "DescendantFonts";
 
980
      objs[nobjs] = wrap;
 
981
      nobjs++;
 
982
 
 
983
      P2POutput::outputDict(fontDict.getDict(),keys,objs,nobjs,str,xref);
 
984
      delete wrap;
 
985
      P2PXRef::put(cidFontDict);
 
986
    } else {
 
987
      P2POutput::outputDict(fontDict.getDict(),keys,objs,nobjs,str,xref);
 
988
    }
 
989
  } else {
 
990
    if (embeddedType != font->getType()) {
 
991
      /* change subtype */
 
992
      P2PObj obj;
 
993
      keys[nobjs] = "Subtype";
 
994
      objs[nobjs] = &obj;
 
995
      nobjs++;
 
996
 
 
997
      switch (embeddedType) {
 
998
      case fontTrueType:
 
999
        obj.getObj()->initName(const_cast<char *>("TrueType"));
 
1000
        P2POutput::outputDict(fontDict.getDict(),keys,objs,nobjs,str,xref);
 
1001
        break;
 
1002
      case fontType1:
 
1003
        obj.getObj()->initName(const_cast<char *>("Type1"));
 
1004
        P2POutput::outputDict(fontDict.getDict(),keys,objs,nobjs,str,xref);
 
1005
        break;
 
1006
      case fontCIDType2:
 
1007
      case fontCIDType0:
 
1008
      case fontCIDType0C:
 
1009
        /* change is not needed */
 
1010
        P2POutput::outputDict(fontDict.getDict(),keys,objs,nobjs,str,xref);
 
1011
        break;
 
1012
      case fontType1C:
 
1013
      case fontUnknownType:
 
1014
      case fontType3:
 
1015
      default:
 
1016
        p2pError(-1,const_cast<char *>("P2PFontDict: Illegal embedded font type"));
 
1017
        return;
 
1018
        break;
 
1019
      }
 
1020
    } else {
 
1021
      P2POutput::outputDict(fontDict.getDict(),keys,objs,nobjs,str,xref);
 
1022
    }
 
1023
  }
 
1024
  str->putchar('\n');
 
1025
  outputEnd(str);
 
1026
}
 
1027
 
 
1028
P2PFontDict::P2PFontDict(Object *fontDictA, XRef *xref, int num, int gen)
 
1029
  : P2PObject(num,gen)
 
1030
{
 
1031
  Ref embID;
 
1032
  Ref id;
 
1033
  Dict *dict;
 
1034
  Object name;
 
1035
  GfxFontType type;
 
1036
 
 
1037
  font = 0;
 
1038
  fontDescriptor = 0;
 
1039
  cidFontDict = 0;
 
1040
  if (fontDictA == 0 || !fontDictA->isDict()) return;
 
1041
  fontDictA->copy(&fontDict);
 
1042
 
 
1043
  dict = fontDict.getDict();
 
1044
  dict->lookup(const_cast<char *>("BaseFont"),&name);
 
1045
  if (!name.isName()) {
 
1046
    p2pError(-1,const_cast<char *>("FontDictionary has not name type BaseFont entry\n"));
 
1047
    goto end_setup;
 
1048
  }
 
1049
  /* font id and tag are not used */
 
1050
  if ((font = GfxFont::makeFont(xref,const_cast<char *>(""),
 
1051
          id,fontDict.getDict())) == 0) {
 
1052
    p2pError(-1,const_cast<char *>("Can't get font %s. Not embedded\n"),
 
1053
      name.getName());
 
1054
    goto end_setup;
 
1055
  }
 
1056
  embeddedType = type = font->getType();
 
1057
  if (!font->getEmbeddedFontID(&embID)) {
 
1058
    /* not embedded */
 
1059
    int i;
 
1060
    const char *namep = name.getName();
 
1061
 
 
1062
//fprintf(stderr,"DEBUG:%s is not embedded\n",name.getName());
 
1063
 
 
1064
    /* check builtin fonts */
 
1065
    for (i = 0;i < nBuiltinFonts;i++) {
 
1066
      if (strcmp(namep, builtinFonts[i].name) == 0) {
 
1067
        /* built in font */
 
1068
        /* don't embed built in font */
 
1069
        fprintf(stderr,"INFO:%s is builtin font. not embedded.\n",namep);
 
1070
        goto end_setup;
 
1071
      }
 
1072
    }
 
1073
 
 
1074
    if (!P2PDoc::options.fontEmbeddingPreLoad) {
 
1075
      /* check pre-loaded fonts */
 
1076
      for (i = 0;i < P2PDoc::options.numPreFonts;i++) {
 
1077
        if (strcmp(namep, P2PDoc::options.preFonts[i]) == 0) {
 
1078
          /* pre-loaded font */
 
1079
          /* don't embed pre-loaded font */
 
1080
          fprintf(stderr,"INFO:%s is pre-loaded font. not embedded.\n",namep);
 
1081
          goto end_setup;
 
1082
        }
 
1083
      }
 
1084
    }
 
1085
 
 
1086
    switch (type) {
 
1087
    case fontType3:
 
1088
      /* Type3 font is always embedded */
 
1089
      /* do nothing */
 
1090
      break;
 
1091
    case fontTrueType:
 
1092
    case fontUnknownType:
 
1093
    case fontType1:
 
1094
    case fontType1C:
 
1095
    case fontType1COT:
 
1096
    case fontTrueTypeOT:
 
1097
      /* 8bit font */
 
1098
      read8bitFontDescriptor(type,name.getName(),xref);
 
1099
      break;
 
1100
    case fontCIDType0:
 
1101
    case fontCIDType0C:
 
1102
    case fontCIDType2:
 
1103
    case fontCIDType0COT:
 
1104
    case fontCIDType2OT:
 
1105
      /* CID font */
 
1106
      readCIDFontDescriptor(type,name.getName(),xref);
 
1107
      break;
 
1108
    }
 
1109
  } else {
 
1110
    /* embedded */
 
1111
  }
 
1112
end_setup:
 
1113
  name.free();
 
1114
}
 
1115
 
 
1116
P2PFontDict::~P2PFontDict()
 
1117
{
 
1118
  if (font != 0) {
 
1119
    font->decRefCnt();
 
1120
  }
 
1121
  /* fontDescriptor is pointed by multiple FontDict,
 
1122
     so, don't delete it here.  it is deleted by P2PXRef::clean() */
 
1123
  /* cidFontDict is pointed by multiple FontDict,
 
1124
     so, don't delete it here.  it is deleted by P2PXRef::clean() */
 
1125
 
 
1126
  fontDict.free();
 
1127
}
 
1128
 
 
1129
void P2PFontDict::showText(GooString *s)
 
1130
{
 
1131
  char *p;
 
1132
  int len;
 
1133
  int n;
 
1134
#ifdef OLD_MAPTOUNICODE
 
1135
  Unicode u[8];
 
1136
#else
 
1137
  Unicode *u = NULL;
 
1138
#endif
 
1139
  CharCode code;
 
1140
  int uLen;
 
1141
  double dx,dy,originX,originY;
 
1142
  P2PFontFile *fontFile;
 
1143
 
 
1144
  if (font == 0 || fontDescriptor == 0) return;
 
1145
  if ((fontFile = fontDescriptor->getFontFile()) == 0) return;
 
1146
  p = s->getCString();
 
1147
  len = s->getLength();
 
1148
  while (len > 0) {
 
1149
#ifdef OLD_MAPTOUNICODE
 
1150
    n = font->getNextChar(p,len,&code,u,(sizeof(u)/sizeof(Unicode)),&uLen,
 
1151
         &dx,&dy,&originX,&originY);
 
1152
#else
 
1153
    n = font->getNextChar(p,len,&code,&u,&uLen,
 
1154
         &dx,&dy,&originX,&originY);
 
1155
#endif
 
1156
    code &= (CIDTOGID_SIZE-1); /* mask */
 
1157
    fontFile->refChar(code);
 
1158
    p += n;
 
1159
    len -= n;
 
1160
  }
 
1161
}
 
1162
 
 
1163
P2PFontResource::P2PFontResource()
 
1164
{
 
1165
  keys = 0;
 
1166
  fontDicts = 0;
 
1167
  nDicts = 0;
 
1168
  nExtGState = 0;
 
1169
  extGStateKeys = 0;
 
1170
  extGStateFonts = 0;
 
1171
}
 
1172
 
 
1173
P2PFontResource::~P2PFontResource()
 
1174
{
 
1175
  int i;
 
1176
 
 
1177
  if (keys != 0) {
 
1178
    for (i = 0;i < nDicts;i++) {
 
1179
      delete keys[i];
 
1180
    }
 
1181
    delete[] keys;
 
1182
  }
 
1183
  if (fontDicts != 0) {
 
1184
    for (i = 0;i < nDicts;i++) {
 
1185
      if (fontDicts[i] != 0) {
 
1186
        int num, gen;
 
1187
 
 
1188
        fontDicts[i]->getNum(&num,&gen);
 
1189
        if (num < 0) {
 
1190
          /* Not indirect referenced FontDict */
 
1191
          /* output it as normal dictionary */
 
1192
          /* so, not needed any more */
 
1193
          delete fontDicts[i];
 
1194
        }
 
1195
        /* indirect referenced FontDict is registered in P2PXRef */
 
1196
        /* So, should not delete it. */
 
1197
      }
 
1198
    }
 
1199
    delete[] fontDicts;
 
1200
  }
 
1201
  if (extGStateKeys != 0) {
 
1202
    for (i = 0;i < nExtGState;i++) {
 
1203
      delete extGStateKeys[i];
 
1204
    }
 
1205
    delete[] extGStateKeys;
 
1206
  }
 
1207
  if (extGStateFonts != 0) {
 
1208
    /* indirect referenced FontDict is registered in P2PXRef */
 
1209
    /* So, should not delete it. */
 
1210
    delete[] extGStateFonts;
 
1211
  }
 
1212
}
 
1213
 
 
1214
void P2PFontResource::setup(P2PResources *resources, XRef *xref)
 
1215
{
 
1216
  doSetup(resources->getFontResource(),xref);
 
1217
  doSetupExtGState(resources->getExtGState(),xref);
 
1218
}
 
1219
 
 
1220
void P2PFontResource::setup(Dict *resources, XRef *xref)
 
1221
{
 
1222
  Object obj;
 
1223
 
 
1224
  if (resources == 0) return;
 
1225
  resources->lookup(const_cast<char *>("Font"),&obj);
 
1226
  if (obj.isDict()) {
 
1227
    doSetup(obj.getDict(),xref);
 
1228
  }
 
1229
  obj.free();
 
1230
  resources->lookup(const_cast<char *>("ExtGState"),&obj);
 
1231
  if (obj.isDict()) {
 
1232
    doSetupExtGState(obj.getDict(),xref);
 
1233
  }
 
1234
  obj.free();
 
1235
}
 
1236
 
 
1237
void P2PFontResource::doSetup(Dict *fontResource, XRef *xref)
 
1238
{
 
1239
  int i;
 
1240
  P2PFontDict *p = 0;
 
1241
 
 
1242
  if (fontResource == 0) return;
 
1243
  nDicts = fontResource->getLength();
 
1244
  keys = new UGooString *[nDicts];
 
1245
  fontDicts = new P2PFontDict *[nDicts];
 
1246
  for (i = 0;i < nDicts;i++) {
 
1247
    Object obj;
 
1248
#ifdef HAVE_UGOOSTRING_H
 
1249
    UGooString *key = fontResource->getKey(i);
 
1250
#else
 
1251
    UGooString *key = new UGooString(fontResource->getKey(i));
 
1252
#endif
 
1253
 
 
1254
    fontResource->getValNF(i,&obj);
 
1255
    if (obj.isRef()) {
 
1256
      int num = obj.getRefNum();
 
1257
      int gen = obj.getRefGen();
 
1258
      if ((p = static_cast<P2PFontDict *>(P2PObject::find(num,gen))) == 0) {
 
1259
        Object fobj;
 
1260
 
 
1261
        xref->fetch(num,gen,&fobj);
 
1262
        if (fobj.isDict()) {
 
1263
          p = new P2PFontDict(&fobj,xref,num,gen);
 
1264
          /* register this in P2PXRef to output later */
 
1265
          P2PXRef::put(p);
 
1266
        }
 
1267
        fobj.free();
 
1268
      }
 
1269
    }
 
1270
    if (p != 0) {
 
1271
      keys[i] = new UGooString(*key);
 
1272
      fontDicts[i] = p;
 
1273
    } else if (obj.isDict()) {
 
1274
      keys[i] = new UGooString(*key);
 
1275
      fontDicts[i] = new P2PFontDict(&obj,xref);
 
1276
      P2PXRef::put(fontDicts[i]);
 
1277
    } else {
 
1278
      keys[i] = 0;
 
1279
      fontDicts[i] = 0;
 
1280
    }
 
1281
    obj.free();
 
1282
  }
 
1283
}
 
1284
 
 
1285
void P2PFontResource::doSetupExtGState(Dict *extGState, XRef *xref)
 
1286
{
 
1287
  int i;
 
1288
  P2PFontDict *p = 0;
 
1289
 
 
1290
  if (extGState == 0) return;
 
1291
  nExtGState = extGState->getLength();
 
1292
  extGStateKeys = new UGooString *[nExtGState];
 
1293
  extGStateFonts = new P2PFontDict *[nExtGState];
 
1294
  for (i = 0;i < nExtGState;i++) {
 
1295
    Object gstateObj;
 
1296
#ifdef HAVE_UGOOSTRING_H
 
1297
    UGooString *key = extGState->getKey(i);
 
1298
#else
 
1299
    char *key = extGState->getKey(i);
 
1300
#endif
 
1301
 
 
1302
    extGStateKeys[i] = 0;
 
1303
    extGStateFonts[i] = 0;
 
1304
    extGState->getVal(i,&gstateObj);
 
1305
    if (gstateObj.isDict()) {
 
1306
      Object fontArrayObj;
 
1307
      Dict *gstate = gstateObj.getDict();
 
1308
 
 
1309
      if (gstate->lookup(const_cast<char *>("Font"),&fontArrayObj) != 0) {
 
1310
        if (fontArrayObj.isArray() && fontArrayObj.arrayGetLength() > 0) {
 
1311
          Object fontRefObj;
 
1312
 
 
1313
          if (fontArrayObj.arrayGetNF(0,&fontRefObj) && fontRefObj.isRef()) {
 
1314
            int num = fontRefObj.getRefNum();
 
1315
            int gen = fontRefObj.getRefGen();
 
1316
 
 
1317
            if ((p = static_cast<P2PFontDict *>(P2PObject::find(num,gen)))
 
1318
                 == 0) {
 
1319
              Object fontObj;
 
1320
              xref->fetch(num,gen,&fontObj);
 
1321
              if (fontObj.isDict()) {
 
1322
                p = new P2PFontDict(&fontObj,xref,num,gen);
 
1323
                /* register this in P2PXRef to output later */
 
1324
                P2PXRef::put(p);
 
1325
              }
 
1326
              fontObj.free();
 
1327
            }
 
1328
          }
 
1329
          fontRefObj.free();
 
1330
        }
 
1331
#ifdef HAVE_UGOOSTRING_H
 
1332
        extGStateKeys[i] = new UGooString(*key);
 
1333
#else
 
1334
        extGStateKeys[i] = new UGooString(key);
 
1335
#endif
 
1336
        extGStateFonts[i] = p;
 
1337
      }
 
1338
      fontArrayObj.free();
 
1339
    }
 
1340
    gstateObj.free();
 
1341
  }
 
1342
}
 
1343
 
 
1344
void P2PFontResource::output(P2POutputStream *str, XRef *xref)
 
1345
{
 
1346
  int i;
 
1347
 
 
1348
  str->puts("<< ");
 
1349
  for (i = 0;i < nDicts;i++) {
 
1350
    P2POutput::outputName(keys[i]->getCString(),str);
 
1351
    str->putchar(' ');
 
1352
    fontDicts[i]->outputRef(str);
 
1353
    str->putchar('\n');
 
1354
  }
 
1355
  str->puts(" >>");
 
1356
}
 
1357
 
 
1358
P2PFontDict *P2PFontResource::lookup(const UGooString &key)
 
1359
{
 
1360
  int i;
 
1361
 
 
1362
  for (i = 0;i < nDicts;i++) {
 
1363
    if (key.cmp(keys[i]) == 0) {
 
1364
      return fontDicts[i];
 
1365
    }
 
1366
  }
 
1367
  return 0;
 
1368
}
 
1369
 
 
1370
P2PFontDict *P2PFontResource::lookupExtGState(const UGooString &key)
 
1371
{
 
1372
  int i;
 
1373
 
 
1374
  for (i = 0;i < nExtGState;i++) {
 
1375
    if (extGStateKeys != 0 && key.cmp(extGStateKeys[i]) == 0) {
 
1376
      return extGStateFonts[i];
 
1377
    }
 
1378
  }
 
1379
  return 0;
 
1380
}