update for HEAD-2003050101
[reactos.git] / lib / freetype / src / cid / cidload.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  cidload.c                                                              */
4 /*                                                                         */
5 /*    CID-keyed Type1 font loader (body).                                  */
6 /*                                                                         */
7 /*  Copyright 1996-2001, 2002 by                                           */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_CONFIG_CONFIG_H
22 #include FT_MULTIPLE_MASTERS_H
23 #include FT_INTERNAL_TYPE1_TYPES_H
24
25 #include "cidload.h"
26
27 #include "ciderrs.h"
28
29
30   /*************************************************************************/
31   /*                                                                       */
32   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
33   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
34   /* messages during execution.                                            */
35   /*                                                                       */
36 #undef  FT_COMPONENT
37 #define FT_COMPONENT  trace_cidload
38
39
40   /* read a single offset */
41   FT_LOCAL_DEF( FT_Long )
42   cid_get_offset( FT_Byte**  start,
43                   FT_Byte    offsize )
44   {
45     FT_Long   result;
46     FT_Byte*  p = *start;
47
48
49     for ( result = 0; offsize > 0; offsize-- )
50     {
51       result <<= 8;
52       result  |= *p++;
53     }
54
55     *start = p;
56     return result;
57   }
58
59
60   FT_LOCAL_DEF( void )
61   cid_decrypt( FT_Byte*   buffer,
62                FT_Offset  length,
63                FT_UShort  seed )
64   {
65     while ( length > 0 )
66     {
67       FT_Byte  plain;
68
69
70       plain     = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
71       seed      = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
72       *buffer++ = plain;
73       length--;
74     }
75   }
76
77
78   /*************************************************************************/
79   /*************************************************************************/
80   /*****                                                               *****/
81   /*****                    TYPE 1 SYMBOL PARSING                      *****/
82   /*****                                                               *****/
83   /*************************************************************************/
84   /*************************************************************************/
85
86
87   static FT_Error
88   cid_load_keyword( CID_Face        face,
89                     CID_Loader*     loader,
90                     const T1_Field  keyword )
91   {
92     FT_Error      error;
93     CID_Parser*   parser = &loader->parser;
94     FT_Byte*      object;
95     void*         dummy_object;
96     CID_FaceInfo  cid = &face->cid;
97
98
99     /* if the keyword has a dedicated callback, call it */
100     if ( keyword->type == T1_FIELD_TYPE_CALLBACK )
101     {
102       keyword->reader( (FT_Face)face, parser );
103       error = parser->root.error;
104       goto Exit;
105     }
106
107     /* we must now compute the address of our target object */
108     switch ( keyword->location )
109     {
110     case T1_FIELD_LOCATION_CID_INFO:
111       object = (FT_Byte*)cid;
112       break;
113
114     case T1_FIELD_LOCATION_FONT_INFO:
115       object = (FT_Byte*)&cid->font_info;
116       break;
117
118     default:
119       {
120         CID_FaceDict  dict;
121
122
123         if ( parser->num_dict < 0 )
124         {
125           FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n",
126                      keyword->ident ));
127           error = CID_Err_Syntax_Error;
128           goto Exit;
129         }
130
131         dict = cid->font_dicts + parser->num_dict;
132         switch ( keyword->location )
133         {
134         case T1_FIELD_LOCATION_PRIVATE:
135           object = (FT_Byte*)&dict->private_dict;
136           break;
137
138         default:
139           object = (FT_Byte*)dict;
140         }
141       }
142     }
143
144     dummy_object = object;
145
146     /* now, load the keyword data in the object's field(s) */
147     if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
148          keyword->type == T1_FIELD_TYPE_FIXED_ARRAY   )
149       error = cid_parser_load_field_table( &loader->parser, keyword,
150                                     &dummy_object );
151     else
152       error = cid_parser_load_field( &loader->parser, keyword, &dummy_object );
153   Exit:
154     return error;
155   }
156
157
158   FT_CALLBACK_DEF( FT_Error )
159   parse_font_bbox( CID_Face     face,
160                    CID_Parser*  parser )
161   {
162     FT_Fixed  temp[4];
163     FT_BBox*  bbox = &face->cid.font_bbox;
164
165
166     (void)cid_parser_to_fixed_array( parser, 4, temp, 0 );
167     bbox->xMin = FT_RoundFix( temp[0] );
168     bbox->yMin = FT_RoundFix( temp[1] );
169     bbox->xMax = FT_RoundFix( temp[2] );
170     bbox->yMax = FT_RoundFix( temp[3] );
171
172     return CID_Err_Ok;       /* this is a callback function; */
173                             /* we must return an error code */
174   }
175
176
177   FT_CALLBACK_DEF( FT_Error )
178   parse_font_matrix( CID_Face     face,
179                      CID_Parser*  parser )
180   {
181     FT_Matrix*    matrix;
182     FT_Vector*    offset;
183     CID_FaceDict  dict;
184     FT_Face       root = (FT_Face)&face->root;
185     FT_Fixed      temp[6];
186     FT_Fixed      temp_scale;
187
188
189     if ( parser->num_dict >= 0 )
190     {
191       dict   = face->cid.font_dicts + parser->num_dict;
192       matrix = &dict->font_matrix;
193       offset = &dict->font_offset;
194
195       (void)cid_parser_to_fixed_array( parser, 6, temp, 3 );
196
197       temp_scale = ABS( temp[3] );
198
199       /* Set Units per EM based on FontMatrix values.  We set the value to */
200       /* `1000/temp_scale', because temp_scale was already multiplied by   */
201       /* 1000 (in t1_tofixed(), from psobjs.c).                            */
202       root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L,
203                                         FT_DivFix( temp_scale, 1000 ) ) );
204
205       /* we need to scale the values by 1.0/temp[3] */
206       if ( temp_scale != 0x10000L )
207       {
208         temp[0] = FT_DivFix( temp[0], temp_scale );
209         temp[1] = FT_DivFix( temp[1], temp_scale );
210         temp[2] = FT_DivFix( temp[2], temp_scale );
211         temp[4] = FT_DivFix( temp[4], temp_scale );
212         temp[5] = FT_DivFix( temp[5], temp_scale );
213         temp[3] = 0x10000L;
214       }
215
216       matrix->xx = temp[0];
217       matrix->yx = temp[1];
218       matrix->xy = temp[2];
219       matrix->yy = temp[3];
220
221       /* note that the font offsets are expressed in integer font units */
222       offset->x  = temp[4] >> 16;
223       offset->y  = temp[5] >> 16;
224     }
225
226     return CID_Err_Ok;       /* this is a callback function; */
227                             /* we must return an error code */
228   }
229
230
231   FT_CALLBACK_DEF( FT_Error )
232   parse_fd_array( CID_Face     face,
233                   CID_Parser*  parser )
234   {
235     CID_FaceInfo  cid    = &face->cid;
236     FT_Memory     memory = face->root.memory;
237     FT_Error      error  = CID_Err_Ok;
238     FT_Long       num_dicts;
239
240
241     num_dicts = cid_parser_to_int( parser );
242
243     if ( !cid->font_dicts )
244     {
245       FT_Int  n;
246
247
248       if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) )
249         goto Exit;
250
251       cid->num_dicts = (FT_UInt)num_dicts;
252
253       /* don't forget to set a few defaults */
254       for ( n = 0; n < cid->num_dicts; n++ )
255       {
256         CID_FaceDict  dict = cid->font_dicts + n;
257
258
259         /* default value for lenIV */
260         dict->private_dict.lenIV = 4;
261       }
262     }
263
264   Exit:
265     return error;
266   }
267
268
269   static
270   const T1_FieldRec  cid_field_records[] =
271   {
272
273 #include "cidtoken.h"
274
275     T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
276     T1_FIELD_CALLBACK( "FDArray", parse_fd_array )
277     T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
278     { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
279   };
280
281
282   static int
283   is_alpha( char  c )
284   {
285     return ( ft_isalnum( (int)c ) ||
286              c == '.'             ||
287              c == '_'             );
288   }
289
290
291   static FT_Error
292   cid_parse_dict( CID_Face     face,
293                   CID_Loader*  loader,
294                   FT_Byte*     base,
295                   FT_Long      size )
296   {
297     CID_Parser*  parser = &loader->parser;
298
299
300     parser->root.cursor = base;
301     parser->root.limit  = base + size;
302     parser->root.error  = 0;
303
304     {
305       FT_Byte*  cur   = base;
306       FT_Byte*  limit = cur + size;
307
308
309       for ( ;cur < limit; cur++ )
310       {
311         /* look for `%ADOBeginFontDict' */
312         if ( *cur == '%' && cur + 20 < limit &&
313              ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 )
314         {
315           cur += 17;
316
317           /* if /FDArray was found, then cid->num_dicts is > 0, and */
318           /* we can start increasing parser->num_dict               */
319           if ( face->cid.num_dicts > 0 )
320             parser->num_dict++;
321         }
322         /* look for immediates */
323         else if ( *cur == '/' && cur + 2 < limit )
324         {
325           FT_Byte*  cur2;
326           FT_Int    len;
327
328
329           cur++;
330
331           cur2 = cur;
332           while ( cur2 < limit && is_alpha( *cur2 ) )
333             cur2++;
334
335           len = (FT_Int)( cur2 - cur );
336           if ( len > 0 && len < 22 )
337           {
338             /* now compare the immediate name to the keyword table */
339             T1_Field  keyword = (T1_Field) cid_field_records;
340
341
342             for (;;)
343             {
344               FT_Byte*  name;
345
346
347               name = (FT_Byte*)keyword->ident;
348               if ( !name )
349                 break;
350
351               if ( cur[0] == name[0]                          &&
352                    len == (FT_Int)ft_strlen( (const char*)name ) )
353               {
354                 FT_Int  n;
355
356
357                 for ( n = 1; n < len; n++ )
358                   if ( cur[n] != name[n] )
359                     break;
360
361                 if ( n >= len )
362                 {
363                   /* we found it - run the parsing callback */
364                   parser->root.cursor = cur2;
365                   cid_parser_skip_spaces( parser );
366                   parser->root.error = cid_load_keyword( face,
367                                                          loader,
368                                                          keyword );
369                   if ( parser->root.error )
370                     return parser->root.error;
371
372                   cur = parser->root.cursor;
373                   break;
374                 }
375               }
376               keyword++;
377             }
378           }
379         }
380       }
381     }
382     return parser->root.error;
383   }
384
385
386   /* read the subrmap and the subrs of each font dict */
387   static FT_Error
388   cid_read_subrs( CID_Face  face )
389   {
390     CID_FaceInfo  cid    = &face->cid;
391     FT_Memory     memory = face->root.memory;
392     FT_Stream     stream = face->root.stream;
393     FT_Error      error;
394     FT_Int        n;
395     CID_Subrs     subr;
396     FT_UInt       max_offsets = 0;
397     FT_ULong*     offsets = 0;
398
399
400     if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) )
401       goto Exit;
402
403     subr = face->subrs;
404     for ( n = 0; n < cid->num_dicts; n++, subr++ )
405     {
406       CID_FaceDict  dict  = cid->font_dicts + n;
407       FT_Int        lenIV = dict->private_dict.lenIV;
408       FT_UInt       count, num_subrs = dict->num_subrs;
409       FT_ULong      data_len;
410       FT_Byte*      p;
411
412
413       /* reallocate offsets array if needed */
414       if ( num_subrs + 1 > max_offsets )
415       {
416         FT_UInt  new_max = ( num_subrs + 1 + 3 ) & -4;
417
418
419         if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) )
420           goto Fail;
421
422         max_offsets = new_max;
423       }
424
425       /* read the subrmap's offsets */
426       if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) ||
427            FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes )   )
428         goto Fail;
429
430       p = (FT_Byte*)stream->cursor;
431       for ( count = 0; count <= num_subrs; count++ )
432         offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes );
433
434       FT_FRAME_EXIT();
435
436       /* now, compute the size of subrs charstrings, */
437       /* allocate, and read them                     */
438       data_len = offsets[num_subrs] - offsets[0];
439
440       if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) ||
441                FT_ALLOC( subr->code[0], data_len )   )
442         goto Fail;
443
444       if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) ||
445            FT_STREAM_READ( subr->code[0], data_len )  )
446         goto Fail;
447
448       /* set up pointers */
449       for ( count = 1; count <= num_subrs; count++ )
450       {
451         FT_ULong  len;
452
453
454         len               = offsets[count] - offsets[count - 1];
455         subr->code[count] = subr->code[count - 1] + len;
456       }
457
458       /* decrypt subroutines, but only if lenIV >= 0 */
459       if ( lenIV >= 0 )
460       {
461         for ( count = 0; count < num_subrs; count++ )
462         {
463           FT_ULong  len;
464
465
466           len = offsets[count + 1] - offsets[count];
467           cid_decrypt( subr->code[count], len, 4330 );
468         }
469       }
470
471       subr->num_subrs = num_subrs;
472     }
473
474   Exit:
475     FT_FREE( offsets );
476     return error;
477
478   Fail:
479     if ( face->subrs )
480     {
481       for ( n = 0; n < cid->num_dicts; n++ )
482       {
483         if ( face->subrs[n].code )
484           FT_FREE( face->subrs[n].code[0] );
485
486         FT_FREE( face->subrs[n].code );
487       }
488       FT_FREE( face->subrs );
489     }
490     goto Exit;
491   }
492
493
494   static void
495   t1_init_loader( CID_Loader*  loader,
496                   CID_Face     face )
497   {
498     FT_UNUSED( face );
499
500     FT_MEM_ZERO( loader, sizeof ( *loader ) );
501   }
502
503
504   static void
505   t1_done_loader( CID_Loader*  loader )
506   {
507     CID_Parser*  parser = &loader->parser;
508
509
510     /* finalize parser */
511     cid_parser_done( parser );
512   }
513
514
515   FT_LOCAL_DEF( FT_Error )
516   cid_face_open( CID_Face  face )
517   {
518     CID_Loader   loader;
519     CID_Parser*  parser;
520     FT_Error     error;
521
522
523     t1_init_loader( &loader, face );
524
525     parser = &loader.parser;
526     error = cid_parser_new( parser, face->root.stream, face->root.memory,
527                             (PSAux_Service)face->psaux );
528     if ( error )
529       goto Exit;
530
531     error = cid_parse_dict( face, &loader,
532                             parser->postscript,
533                             parser->postscript_len );
534     if ( error )
535       goto Exit;
536
537     face->cid.data_offset = loader.parser.data_offset;
538     error = cid_read_subrs( face );
539
540   Exit:
541     t1_done_loader( &loader );
542     return error;
543   }
544
545
546 /* END */