update for HEAD-2003021201
[reactos.git] / subsys / win32k / freetype / src / cid / cidload.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  cidload.c                                                              */
4 /*                                                                         */
5 /*    CID-keyed Type1 font loader (body).                                  */
6 /*                                                                         */
7 /*  Copyright 1996-2000 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 <freetype/internal/ftdebug.h>
20 #include <freetype/config/ftconfig.h>
21 #include <freetype/ftmm.h>
22
23 #include <freetype/internal/t1types.h>
24 #include <freetype/internal/t1errors.h>
25
26
27 #ifdef FT_FLAT_COMPILE
28
29 #include "cidload.h"
30
31 #else
32
33 #include <freetype/src/cid/cidload.h>
34
35 #endif
36
37
38 #include <stdio.h>
39 #include <ctype.h>  /* for isspace(), isalnum() */
40
41
42   /*************************************************************************/
43   /*                                                                       */
44   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
45   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
46   /* messages during execution.                                            */
47   /*                                                                       */
48 #undef  FT_COMPONENT
49 #define FT_COMPONENT  trace_cidload
50
51
52   /* read a single offset */
53   LOCAL_FUNC
54   FT_Long  cid_get_offset( FT_Byte**  start,
55                            FT_Byte    offsize )
56   {
57     FT_Long   result;
58     FT_Byte*  p = *start;
59
60
61     for ( result = 0; offsize > 0; offsize-- )
62     {
63       result <<= 8;
64       result  |= *p++;
65     }
66
67     *start = p;
68     return result;
69   }
70
71
72   LOCAL_FUNC
73   void  cid_decrypt( FT_Byte*   buffer,
74                      FT_Int     length,
75                      FT_UShort  seed )
76   {
77     while ( length > 0 )
78     {
79       FT_Byte  plain;
80
81
82       plain     = ( *buffer ^ ( seed >> 8 ) );
83       seed      = ( *buffer + seed ) * 52845 + 22719;
84       *buffer++ = plain;
85       length--;
86     }
87   }
88
89
90   /*************************************************************************/
91   /*************************************************************************/
92   /*****                                                               *****/
93   /*****                    TYPE 1 SYMBOL PARSING                      *****/
94   /*****                                                               *****/
95   /*************************************************************************/
96   /*************************************************************************/
97
98
99   static
100   FT_Error  cid_load_keyword( CID_Face              face,
101                               CID_Loader*           loader,
102                               const CID_Field_Rec*  keyword )
103   {
104     FT_Error     error;
105     CID_Parser*  parser = &loader->parser;
106     FT_Byte*     object;
107     CID_Info*    cid = &face->cid;
108
109
110     /* if the keyword has a dedicated callback, call it */
111     if ( keyword->type == t1_field_callback )
112     {
113       error = keyword->reader( face, parser );
114       goto Exit;
115     }
116
117     /* we must now compute the address of our target object */
118     switch ( keyword->location )
119     {
120     case t1_field_cid_info:
121       object = (FT_Byte*)cid;
122       break;
123
124     case t1_field_font_info:
125       object = (FT_Byte*)&cid->font_info;
126       break;
127
128     default:
129       {
130         CID_FontDict*  dict;
131
132
133         if ( parser->num_dict < 0 )
134         {
135           FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n",
136                      keyword->ident ));
137           error = T1_Err_Syntax_Error;
138           goto Exit;
139         }
140
141         dict = cid->font_dicts + parser->num_dict;
142         switch ( keyword->location )
143         {
144         case t1_field_private:
145           object = (FT_Byte*)&dict->private_dict;
146           break;
147
148         default:
149           object = (FT_Byte*)dict;
150         }
151       }
152     }
153
154     /* now, load the keyword data in the object's field(s) */
155     if ( keyword->type == t1_field_integer_array ||
156          keyword->type == t1_field_fixed_array   )
157       error = CID_Load_Field_Table( parser, keyword, object );
158     else
159       error = CID_Load_Field( parser, keyword, object );
160
161   Exit:
162     return error;
163   }
164
165
166   static
167   FT_Error  parse_font_bbox( CID_Face     face,
168                              CID_Parser*  parser )
169   {
170     FT_Short  temp[4];
171     FT_BBox*  bbox = &face->cid.font_bbox;
172
173
174     (void)CID_ToCoordArray( parser, 4, temp );
175     bbox->xMin = temp[0];
176     bbox->yMin = temp[1];
177     bbox->xMax = temp[2];
178     bbox->yMax = temp[3];
179
180     return T1_Err_Ok;       /* this is a callback function; */
181                             /* we must return an error code */
182   }
183
184
185   static
186   FT_Error  parse_font_matrix( CID_Face     face,
187                                CID_Parser*  parser )
188   {
189     FT_Matrix*     matrix;
190     CID_FontDict*  dict;
191     FT_Fixed       temp[4];
192
193
194     if ( parser->num_dict >= 0 )
195     {
196       dict   = face->cid.font_dicts + parser->num_dict;
197       matrix = &dict->font_matrix;
198
199       (void)CID_ToFixedArray( parser, 4, temp, 3 );
200       matrix->xx = temp[0];
201       matrix->yx = temp[1];
202       matrix->xy = temp[2];
203       matrix->yy = temp[3];
204     }
205
206     return T1_Err_Ok;       /* this is a callback function; */
207                             /* we must return an error code */
208   }
209
210
211   static
212   FT_Error  parse_fd_array( CID_Face     face,
213                             CID_Parser*  parser )
214   {
215     CID_Info*  cid    = &face->cid;
216     FT_Memory  memory = face->root.memory;
217     FT_Error   error  = T1_Err_Ok;
218     FT_Long    num_dicts;
219
220
221     num_dicts = CID_ToInt( parser );
222
223     if ( !cid->font_dicts )
224     {
225       FT_Int  n;
226
227
228       if ( ALLOC_ARRAY( cid->font_dicts, num_dicts, CID_FontDict ) )
229         goto Exit;
230
231       cid->num_dicts = (FT_UInt)num_dicts;
232
233       /* don't forget to set a few defaults */
234       for ( n = 0; n < cid->num_dicts; n++ )
235       {
236         CID_FontDict*  dict = cid->font_dicts + n;
237
238
239         /* default value for lenIV */
240         dict->private_dict.lenIV = 4;
241       }
242     }
243
244   Exit:
245     return error;
246   }
247
248
249   static
250   const CID_Field_Rec  t1_field_records[] =
251   {
252
253 #ifdef FT_FLAT_COMPILE
254
255 #include "cidtokens.h"
256
257 #else
258
259 #include <freetype/src/cid/cidtokens.h>
260
261 #endif
262
263     { 0, t1_field_cid_info, t1_field_none, 0, 0, 0, 0, 0 }
264   };
265
266
267   static
268   int  is_alpha( char  c )
269   {
270     return ( isalnum( c ) ||
271              c == '.'     ||
272              c == '_'     );
273   }
274
275
276   static
277   void  skip_whitespace( CID_Parser*  parser )
278   {
279     FT_Byte*  cur = parser->cursor;
280
281
282     while ( cur < parser->limit && isspace( *cur ) )
283       cur++;
284
285     parser->cursor = cur;
286   }
287
288
289   static
290   FT_Error  parse_dict( CID_Face     face,
291                         CID_Loader*  loader,
292                         FT_Byte*     base,
293                         FT_Long      size )
294   {
295     CID_Parser*  parser = &loader->parser;
296
297
298     parser->cursor = base;
299     parser->limit  = base + size;
300     parser->error  = 0;
301
302     {
303       FT_Byte*  cur   = base;
304       FT_Byte*  limit = cur + size;
305
306
307       for ( ;cur < limit; cur++ )
308       {
309         /* look for `%ADOBeginFontDict' */
310         if ( *cur == '%' && cur + 20 < limit &&
311              strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 )
312         {
313           cur += 17;
314
315           /* if /FDArray was found, then cid->num_dicts is > 0, and */
316           /* we can start increasing parser->num_dict               */
317           if ( face->cid.num_dicts > 0 )
318             parser->num_dict++;
319         }
320         /* look for immediates */
321         else if ( *cur == '/' && cur + 2 < limit )
322         {
323           FT_Byte*  cur2;
324           FT_Int    len;
325
326
327           cur++;
328
329           cur2 = cur;
330           while ( cur2 < limit && is_alpha( *cur2 ) )
331             cur2++;
332
333           len = cur2 - cur;
334           if ( len > 0 && len < 22 )
335           {
336             /* now compare the immediate name to the keyword table */
337             const CID_Field_Rec*  keyword = t1_field_records;
338
339
340             for (;;)
341             {
342               FT_Byte*  name;
343
344
345               name = (FT_Byte*)keyword->ident;
346               if ( !name )
347                 break;
348
349               if ( cur[0] == name[0]                          &&
350                    len == (FT_Int)strlen( (const char*)name ) )
351               {
352                 FT_Int  n;
353
354
355                 for ( n = 1; n < len; n++ )
356                   if ( cur[n] != name[n] )
357                     break;
358
359                 if ( n >= len )
360                 {
361                   /* we found it - run the parsing callback */
362                   parser->cursor = cur2;
363                   skip_whitespace( parser );
364                   parser->error = cid_load_keyword( face, loader, keyword );
365                   if ( parser->error )
366                     return parser->error;
367
368                   cur = parser->cursor;
369                   break;
370                 }
371               }
372               keyword++;
373             }
374           }
375         }
376       }
377     }
378     return parser->error;
379   }
380
381
382   /* read the subrmap and the subrs of each font dict */
383   static
384   FT_Error  cid_read_subrs( CID_Face  face )
385   {
386     CID_Info*   cid    = &face->cid;
387     FT_Memory   memory = face->root.memory;
388     FT_Stream   stream = face->root.stream;
389     FT_Error    error;
390     FT_Int      n;
391     CID_Subrs*  subr;
392     FT_UInt     max_offsets = 0;
393     FT_ULong*   offsets = 0;
394
395
396     if ( ALLOC_ARRAY( face->subrs, cid->num_dicts, CID_Subrs ) )
397       goto Exit;
398
399     subr = face->subrs;
400     for ( n = 0; n < cid->num_dicts; n++, subr++ )
401     {
402       CID_FontDict*  dict = cid->font_dicts + n;
403       FT_UInt        count, num_subrs = dict->num_subrs;
404       FT_ULong       data_len;
405       FT_Byte*       p;
406
407
408       /* reallocate offsets array if needed */
409       if ( num_subrs + 1 > max_offsets )
410       {
411         FT_UInt  new_max = ( num_subrs + 1 + 3 ) & -4;
412
413
414         if ( REALLOC_ARRAY( offsets, max_offsets, new_max, FT_ULong ) )
415           goto Fail;
416
417         max_offsets = new_max;
418       }
419
420       /* read the subrmap's offsets */
421       if ( FILE_Seek( cid->data_offset + dict->subrmap_offset ) ||
422            ACCESS_Frame( ( num_subrs + 1 ) * dict->sd_bytes )   )
423         goto Fail;
424
425       p = (FT_Byte*)stream->cursor;
426       for ( count = 0; count <= num_subrs; count++ )
427         offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes );
428
429       FORGET_Frame();
430
431       /* now, compute the size of subrs charstrings, */
432       /* allocate, and read them                     */
433       data_len = offsets[num_subrs] - offsets[0];
434
435       if ( ALLOC_ARRAY( subr->code, num_subrs + 1, FT_Byte* ) ||
436            ALLOC( subr->code[0], data_len )                   )
437         goto Fail;
438
439       if ( FILE_Seek( cid->data_offset + offsets[0] ) ||
440            FILE_Read( subr->code[0], data_len )  )
441         goto Exit;
442
443       /* set up pointers */
444       for ( count = 1; count <= num_subrs; count++ )
445       {
446         FT_UInt  len;
447
448
449         len               = offsets[count] - offsets[count - 1];
450         subr->code[count] = subr->code[count - 1] + len;
451       }
452
453       /* decrypt subroutines */
454       for ( count = 0; count < num_subrs; count++ )
455       {
456         FT_UInt  len;
457
458
459         len = offsets[count + 1] - offsets[count];
460         cid_decrypt( subr->code[count], len, 4330 );
461       }
462
463       subr->num_subrs = num_subrs;
464     }
465
466   Exit:
467     FREE( offsets );
468     return error;
469
470   Fail:
471     if ( face->subrs )
472     {
473       for ( n = 0; n < cid->num_dicts; n++ )
474       {
475         if ( face->subrs[n].code )
476           FREE( face->subrs[n].code[0] );
477
478         FREE( face->subrs[n].code );
479       }
480       FREE( face->subrs );
481     }
482     goto Exit;
483   }
484
485
486   static
487   void t1_init_loader( CID_Loader*  loader,
488                        CID_Face     face )
489   {
490     FT_UNUSED( face );
491
492     MEM_Set( loader, 0, sizeof ( *loader ) );
493   }
494
495
496   static
497   void t1_done_loader( CID_Loader*  loader )
498   {
499     CID_Parser*  parser = &loader->parser;
500
501
502     /* finalize parser */
503     CID_Done_Parser( parser );
504   }
505
506
507   LOCAL_FUNC
508   FT_Error  CID_Open_Face( CID_Face  face )
509   {
510     CID_Loader  loader;
511     CID_Parser* parser;
512     FT_Error   error;
513
514
515     t1_init_loader( &loader, face );
516
517     parser = &loader.parser;
518     error = CID_New_Parser( parser, face->root.stream, face->root.memory );
519     if ( error )
520       goto Exit;
521
522     error = parse_dict( face, &loader,
523                         parser->postscript,
524                         parser->postscript_len );
525     if ( error )
526       goto Exit;
527
528     face->cid.data_offset = loader.parser.data_offset;
529     error = cid_read_subrs( face );
530
531   Exit:
532     t1_done_loader( &loader );
533     return error;
534   }
535
536
537 /* END */