~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to tests/freetype/src/psaux/psobjs.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************/
 
2
/*                                                                         */
 
3
/*  psobjs.c                                                               */
 
4
/*                                                                         */
 
5
/*    Auxiliary functions for PostScript fonts (body).                     */
 
6
/*                                                                         */
 
7
/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,   */
 
8
/*            2010 by                                                      */
 
9
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 
10
/*                                                                         */
 
11
/*  This file is part of the FreeType project, and may only be used,       */
 
12
/*  modified, and distributed under the terms of the FreeType project      */
 
13
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
 
14
/*  this file you indicate that you have read the license and              */
 
15
/*  understand and accept it fully.                                        */
 
16
/*                                                                         */
 
17
/***************************************************************************/
 
18
 
 
19
 
 
20
#include <ft2build.h>
 
21
#include FT_INTERNAL_POSTSCRIPT_AUX_H
 
22
#include FT_INTERNAL_DEBUG_H
 
23
#include FT_INTERNAL_CALC_H
 
24
 
 
25
#include "psobjs.h"
 
26
#include "psconv.h"
 
27
 
 
28
#include "psauxerr.h"
 
29
 
 
30
 
 
31
  /*************************************************************************/
 
32
  /*                                                                       */
 
33
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
 
34
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
 
35
  /* messages during execution.                                            */
 
36
  /*                                                                       */
 
37
#undef  FT_COMPONENT
 
38
#define FT_COMPONENT  trace_psobjs
 
39
 
 
40
 
 
41
  /*************************************************************************/
 
42
  /*************************************************************************/
 
43
  /*****                                                               *****/
 
44
  /*****                             PS_TABLE                          *****/
 
45
  /*****                                                               *****/
 
46
  /*************************************************************************/
 
47
  /*************************************************************************/
 
48
 
 
49
  /*************************************************************************/
 
50
  /*                                                                       */
 
51
  /* <Function>                                                            */
 
52
  /*    ps_table_new                                                       */
 
53
  /*                                                                       */
 
54
  /* <Description>                                                         */
 
55
  /*    Initializes a PS_Table.                                            */
 
56
  /*                                                                       */
 
57
  /* <InOut>                                                               */
 
58
  /*    table  :: The address of the target table.                         */
 
59
  /*                                                                       */
 
60
  /* <Input>                                                               */
 
61
  /*    count  :: The table size = the maximum number of elements.         */
 
62
  /*                                                                       */
 
63
  /*    memory :: The memory object to use for all subsequent              */
 
64
  /*              reallocations.                                           */
 
65
  /*                                                                       */
 
66
  /* <Return>                                                              */
 
67
  /*    FreeType error code.  0 means success.                             */
 
68
  /*                                                                       */
 
69
  FT_LOCAL_DEF( FT_Error )
 
70
  ps_table_new( PS_Table   table,
 
71
                FT_Int     count,
 
72
                FT_Memory  memory )
 
73
  {
 
74
    FT_Error  error;
 
75
 
 
76
 
 
77
    table->memory = memory;
 
78
    if ( FT_NEW_ARRAY( table->elements, count ) ||
 
79
         FT_NEW_ARRAY( table->lengths,  count ) )
 
80
      goto Exit;
 
81
 
 
82
    table->max_elems = count;
 
83
    table->init      = 0xDEADBEEFUL;
 
84
    table->num_elems = 0;
 
85
    table->block     = 0;
 
86
    table->capacity  = 0;
 
87
    table->cursor    = 0;
 
88
 
 
89
    *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs;
 
90
 
 
91
  Exit:
 
92
    if ( error )
 
93
      FT_FREE( table->elements );
 
94
 
 
95
    return error;
 
96
  }
 
97
 
 
98
 
 
99
  static void
 
100
  shift_elements( PS_Table  table,
 
101
                  FT_Byte*  old_base )
 
102
  {
 
103
    FT_PtrDist  delta  = table->block - old_base;
 
104
    FT_Byte**   offset = table->elements;
 
105
    FT_Byte**   limit  = offset + table->max_elems;
 
106
 
 
107
 
 
108
    for ( ; offset < limit; offset++ )
 
109
    {
 
110
      if ( offset[0] )
 
111
        offset[0] += delta;
 
112
    }
 
113
  }
 
114
 
 
115
 
 
116
  static FT_Error
 
117
  reallocate_t1_table( PS_Table  table,
 
118
                       FT_Long   new_size )
 
119
  {
 
120
    FT_Memory  memory   = table->memory;
 
121
    FT_Byte*   old_base = table->block;
 
122
    FT_Error   error;
 
123
 
 
124
 
 
125
    /* allocate new base block */
 
126
    if ( FT_ALLOC( table->block, new_size ) )
 
127
    {
 
128
      table->block = old_base;
 
129
      return error;
 
130
    }
 
131
 
 
132
    /* copy elements and shift offsets */
 
133
    if ( old_base )
 
134
    {
 
135
      FT_MEM_COPY( table->block, old_base, table->capacity );
 
136
      shift_elements( table, old_base );
 
137
      FT_FREE( old_base );
 
138
    }
 
139
 
 
140
    table->capacity = new_size;
 
141
 
 
142
    return PSaux_Err_Ok;
 
143
  }
 
144
 
 
145
 
 
146
  /*************************************************************************/
 
147
  /*                                                                       */
 
148
  /* <Function>                                                            */
 
149
  /*    ps_table_add                                                       */
 
150
  /*                                                                       */
 
151
  /* <Description>                                                         */
 
152
  /*    Adds an object to a PS_Table, possibly growing its memory block.   */
 
153
  /*                                                                       */
 
154
  /* <InOut>                                                               */
 
155
  /*    table  :: The target table.                                        */
 
156
  /*                                                                       */
 
157
  /* <Input>                                                               */
 
158
  /*    idx    :: The index of the object in the table.                    */
 
159
  /*                                                                       */
 
160
  /*    object :: The address of the object to copy in memory.             */
 
161
  /*                                                                       */
 
162
  /*    length :: The length in bytes of the source object.                */
 
163
  /*                                                                       */
 
164
  /* <Return>                                                              */
 
165
  /*    FreeType error code.  0 means success.  An error is returned if a  */
 
166
  /*    reallocation fails.                                                */
 
167
  /*                                                                       */
 
168
  FT_LOCAL_DEF( FT_Error )
 
169
  ps_table_add( PS_Table    table,
 
170
                FT_Int      idx,
 
171
                void*       object,
 
172
                FT_PtrDist  length )
 
173
  {
 
174
    if ( idx < 0 || idx >= table->max_elems )
 
175
    {
 
176
      FT_ERROR(( "ps_table_add: invalid index\n" ));
 
177
      return PSaux_Err_Invalid_Argument;
 
178
    }
 
179
 
 
180
    if ( length < 0 )
 
181
    {
 
182
      FT_ERROR(( "ps_table_add: invalid length\n" ));
 
183
      return PSaux_Err_Invalid_Argument;
 
184
    }
 
185
 
 
186
    /* grow the base block if needed */
 
187
    if ( table->cursor + length > table->capacity )
 
188
    {
 
189
      FT_Error   error;
 
190
      FT_Offset  new_size = table->capacity;
 
191
      FT_Long    in_offset;
 
192
 
 
193
 
 
194
      in_offset = (FT_Long)((FT_Byte*)object - table->block);
 
195
      if ( (FT_ULong)in_offset >= table->capacity )
 
196
        in_offset = -1;
 
197
 
 
198
      while ( new_size < table->cursor + length )
 
199
      {
 
200
        /* increase size by 25% and round up to the nearest multiple
 
201
           of 1024 */
 
202
        new_size += ( new_size >> 2 ) + 1;
 
203
        new_size  = FT_PAD_CEIL( new_size, 1024 );
 
204
      }
 
205
 
 
206
      error = reallocate_t1_table( table, new_size );
 
207
      if ( error )
 
208
        return error;
 
209
 
 
210
      if ( in_offset >= 0 )
 
211
        object = table->block + in_offset;
 
212
    }
 
213
 
 
214
    /* add the object to the base block and adjust offset */
 
215
    table->elements[idx] = table->block + table->cursor;
 
216
    table->lengths [idx] = length;
 
217
    FT_MEM_COPY( table->block + table->cursor, object, length );
 
218
 
 
219
    table->cursor += length;
 
220
    return PSaux_Err_Ok;
 
221
  }
 
222
 
 
223
 
 
224
  /*************************************************************************/
 
225
  /*                                                                       */
 
226
  /* <Function>                                                            */
 
227
  /*    ps_table_done                                                      */
 
228
  /*                                                                       */
 
229
  /* <Description>                                                         */
 
230
  /*    Finalizes a PS_TableRec (i.e., reallocate it to its current        */
 
231
  /*    cursor).                                                           */
 
232
  /*                                                                       */
 
233
  /* <InOut>                                                               */
 
234
  /*    table :: The target table.                                         */
 
235
  /*                                                                       */
 
236
  /* <Note>                                                                */
 
237
  /*    This function does NOT release the heap's memory block.  It is up  */
 
238
  /*    to the caller to clean it, or reference it in its own structures.  */
 
239
  /*                                                                       */
 
240
  FT_LOCAL_DEF( void )
 
241
  ps_table_done( PS_Table  table )
 
242
  {
 
243
    FT_Memory  memory = table->memory;
 
244
    FT_Error   error;
 
245
    FT_Byte*   old_base = table->block;
 
246
 
 
247
 
 
248
    /* should never fail, because rec.cursor <= rec.size */
 
249
    if ( !old_base )
 
250
      return;
 
251
 
 
252
    if ( FT_ALLOC( table->block, table->cursor ) )
 
253
      return;
 
254
    FT_MEM_COPY( table->block, old_base, table->cursor );
 
255
    shift_elements( table, old_base );
 
256
 
 
257
    table->capacity = table->cursor;
 
258
    FT_FREE( old_base );
 
259
 
 
260
    FT_UNUSED( error );
 
261
  }
 
262
 
 
263
 
 
264
  FT_LOCAL_DEF( void )
 
265
  ps_table_release( PS_Table  table )
 
266
  {
 
267
    FT_Memory  memory = table->memory;
 
268
 
 
269
 
 
270
    if ( (FT_ULong)table->init == 0xDEADBEEFUL )
 
271
    {
 
272
      FT_FREE( table->block );
 
273
      FT_FREE( table->elements );
 
274
      FT_FREE( table->lengths );
 
275
      table->init = 0;
 
276
    }
 
277
  }
 
278
 
 
279
 
 
280
  /*************************************************************************/
 
281
  /*************************************************************************/
 
282
  /*****                                                               *****/
 
283
  /*****                            T1 PARSER                          *****/
 
284
  /*****                                                               *****/
 
285
  /*************************************************************************/
 
286
  /*************************************************************************/
 
287
 
 
288
 
 
289
  /* first character must be already part of the comment */
 
290
 
 
291
  static void
 
292
  skip_comment( FT_Byte*  *acur,
 
293
                FT_Byte*   limit )
 
294
  {
 
295
    FT_Byte*  cur = *acur;
 
296
 
 
297
 
 
298
    while ( cur < limit )
 
299
    {
 
300
      if ( IS_PS_NEWLINE( *cur ) )
 
301
        break;
 
302
      cur++;
 
303
    }
 
304
 
 
305
    *acur = cur;
 
306
  }
 
307
 
 
308
 
 
309
  static void
 
310
  skip_spaces( FT_Byte*  *acur,
 
311
               FT_Byte*   limit )
 
312
  {
 
313
    FT_Byte*  cur = *acur;
 
314
 
 
315
 
 
316
    while ( cur < limit )
 
317
    {
 
318
      if ( !IS_PS_SPACE( *cur ) )
 
319
      {
 
320
        if ( *cur == '%' )
 
321
          /* According to the PLRM, a comment is equal to a space. */
 
322
          skip_comment( &cur, limit );
 
323
        else
 
324
          break;
 
325
      }
 
326
      cur++;
 
327
    }
 
328
 
 
329
    *acur = cur;
 
330
  }
 
331
 
 
332
 
 
333
#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
 
334
 
 
335
 
 
336
  /* first character must be `(';                               */
 
337
  /* *acur is positioned at the character after the closing `)' */
 
338
 
 
339
  static FT_Error
 
340
  skip_literal_string( FT_Byte*  *acur,
 
341
                       FT_Byte*   limit )
 
342
  {
 
343
    FT_Byte*      cur   = *acur;
 
344
    FT_Int        embed = 0;
 
345
    FT_Error      error = PSaux_Err_Invalid_File_Format;
 
346
    unsigned int  i;
 
347
 
 
348
 
 
349
    while ( cur < limit )
 
350
    {
 
351
      FT_Byte  c = *cur;
 
352
 
 
353
 
 
354
      ++cur;
 
355
 
 
356
      if ( c == '\\' )
 
357
      {
 
358
        /* Red Book 3rd ed., section `Literal Text Strings', p. 29:     */
 
359
        /* A backslash can introduce three different types              */
 
360
        /* of escape sequences:                                         */
 
361
        /*   - a special escaped char like \r, \n, etc.                 */
 
362
        /*   - a one-, two-, or three-digit octal number                */
 
363
        /*   - none of the above in which case the backslash is ignored */
 
364
 
 
365
        if ( cur == limit )
 
366
          /* error (or to be ignored?) */
 
367
          break;
 
368
 
 
369
        switch ( *cur )
 
370
        {
 
371
          /* skip `special' escape */
 
372
        case 'n':
 
373
        case 'r':
 
374
        case 't':
 
375
        case 'b':
 
376
        case 'f':
 
377
        case '\\':
 
378
        case '(':
 
379
        case ')':
 
380
          ++cur;
 
381
          break;
 
382
 
 
383
        default:
 
384
          /* skip octal escape or ignore backslash */
 
385
          for ( i = 0; i < 3 && cur < limit; ++i )
 
386
          {
 
387
            if ( !IS_OCTAL_DIGIT( *cur ) )
 
388
              break;
 
389
 
 
390
            ++cur;
 
391
          }
 
392
        }
 
393
      }
 
394
      else if ( c == '(' )
 
395
        embed++;
 
396
      else if ( c == ')' )
 
397
      {
 
398
        embed--;
 
399
        if ( embed == 0 )
 
400
        {
 
401
          error = PSaux_Err_Ok;
 
402
          break;
 
403
        }
 
404
      }
 
405
    }
 
406
 
 
407
    *acur = cur;
 
408
 
 
409
    return error;
 
410
  }
 
411
 
 
412
 
 
413
  /* first character must be `<' */
 
414
 
 
415
  static FT_Error
 
416
  skip_string( FT_Byte*  *acur,
 
417
               FT_Byte*   limit )
 
418
  {
 
419
    FT_Byte*  cur = *acur;
 
420
    FT_Error  err =  PSaux_Err_Ok;
 
421
 
 
422
 
 
423
    while ( ++cur < limit )
 
424
    {
 
425
      /* All whitespace characters are ignored. */
 
426
      skip_spaces( &cur, limit );
 
427
      if ( cur >= limit )
 
428
        break;
 
429
 
 
430
      if ( !IS_PS_XDIGIT( *cur ) )
 
431
        break;
 
432
    }
 
433
 
 
434
    if ( cur < limit && *cur != '>' )
 
435
    {
 
436
      FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
 
437
      err = PSaux_Err_Invalid_File_Format;
 
438
    }
 
439
    else
 
440
      cur++;
 
441
 
 
442
    *acur = cur;
 
443
    return err;
 
444
  }
 
445
 
 
446
 
 
447
  /* first character must be the opening brace that */
 
448
  /* starts the procedure                           */
 
449
 
 
450
  /* NB: [ and ] need not match:                    */
 
451
  /* `/foo {[} def' is a valid PostScript fragment, */
 
452
  /* even within a Type1 font                       */
 
453
 
 
454
  static FT_Error
 
455
  skip_procedure( FT_Byte*  *acur,
 
456
                  FT_Byte*   limit )
 
457
  {
 
458
    FT_Byte*  cur;
 
459
    FT_Int    embed = 0;
 
460
    FT_Error  error = PSaux_Err_Ok;
 
461
 
 
462
 
 
463
    FT_ASSERT( **acur == '{' );
 
464
 
 
465
    for ( cur = *acur; cur < limit && error == PSaux_Err_Ok; ++cur )
 
466
    {
 
467
      switch ( *cur )
 
468
      {
 
469
      case '{':
 
470
        ++embed;
 
471
        break;
 
472
 
 
473
      case '}':
 
474
        --embed;
 
475
        if ( embed == 0 )
 
476
        {
 
477
          ++cur;
 
478
          goto end;
 
479
        }
 
480
        break;
 
481
 
 
482
      case '(':
 
483
        error = skip_literal_string( &cur, limit );
 
484
        break;
 
485
 
 
486
      case '<':
 
487
        error = skip_string( &cur, limit );
 
488
        break;
 
489
 
 
490
      case '%':
 
491
        skip_comment( &cur, limit );
 
492
        break;
 
493
      }
 
494
    }
 
495
 
 
496
  end:
 
497
    if ( embed != 0 )
 
498
      error = PSaux_Err_Invalid_File_Format;
 
499
 
 
500
    *acur = cur;
 
501
 
 
502
    return error;
 
503
  }
 
504
 
 
505
 
 
506
  /***********************************************************************/
 
507
  /*                                                                     */
 
508
  /* All exported parsing routines handle leading whitespace and stop at */
 
509
  /* the first character which isn't part of the just handled token.     */
 
510
  /*                                                                     */
 
511
  /***********************************************************************/
 
512
 
 
513
 
 
514
  FT_LOCAL_DEF( void )
 
515
  ps_parser_skip_PS_token( PS_Parser  parser )
 
516
  {
 
517
    /* Note: PostScript allows any non-delimiting, non-whitespace        */
 
518
    /*       character in a name (PS Ref Manual, 3rd ed, p31).           */
 
519
    /*       PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
 
520
 
 
521
    FT_Byte*  cur   = parser->cursor;
 
522
    FT_Byte*  limit = parser->limit;
 
523
    FT_Error  error = PSaux_Err_Ok;
 
524
 
 
525
 
 
526
    skip_spaces( &cur, limit );             /* this also skips comments */
 
527
    if ( cur >= limit )
 
528
      goto Exit;
 
529
 
 
530
    /* self-delimiting, single-character tokens */
 
531
    if ( *cur == '[' || *cur == ']' )
 
532
    {
 
533
      cur++;
 
534
      goto Exit;
 
535
    }
 
536
 
 
537
    /* skip balanced expressions (procedures and strings) */
 
538
 
 
539
    if ( *cur == '{' )                              /* {...} */
 
540
    {
 
541
      error = skip_procedure( &cur, limit );
 
542
      goto Exit;
 
543
    }
 
544
 
 
545
    if ( *cur == '(' )                              /* (...) */
 
546
    {
 
547
      error = skip_literal_string( &cur, limit );
 
548
      goto Exit;
 
549
    }
 
550
 
 
551
    if ( *cur == '<' )                              /* <...> */
 
552
    {
 
553
      if ( cur + 1 < limit && *(cur + 1) == '<' )   /* << */
 
554
      {
 
555
        cur++;
 
556
        cur++;
 
557
      }
 
558
      else
 
559
        error = skip_string( &cur, limit );
 
560
 
 
561
      goto Exit;
 
562
    }
 
563
 
 
564
    if ( *cur == '>' )
 
565
    {
 
566
      cur++;
 
567
      if ( cur >= limit || *cur != '>' )             /* >> */
 
568
      {
 
569
        FT_ERROR(( "ps_parser_skip_PS_token:"
 
570
                   " unexpected closing delimiter `>'\n" ));
 
571
        error = PSaux_Err_Invalid_File_Format;
 
572
        goto Exit;
 
573
      }
 
574
      cur++;
 
575
      goto Exit;
 
576
    }
 
577
 
 
578
    if ( *cur == '/' )
 
579
      cur++;
 
580
 
 
581
    /* anything else */
 
582
    while ( cur < limit )
 
583
    {
 
584
      /* *cur might be invalid (e.g., ')' or '}'), but this   */
 
585
      /* is handled by the test `cur == parser->cursor' below */
 
586
      if ( IS_PS_DELIM( *cur ) )
 
587
        break;
 
588
 
 
589
      cur++;
 
590
    }
 
591
 
 
592
  Exit:
 
593
    if ( cur == parser->cursor )
 
594
    {
 
595
      FT_ERROR(( "ps_parser_skip_PS_token:"
 
596
                 " current token is `%c' which is self-delimiting\n"
 
597
                 "                        "
 
598
                 " but invalid at this point\n",
 
599
                 *cur ));
 
600
 
 
601
      error = PSaux_Err_Invalid_File_Format;
 
602
    }
 
603
 
 
604
    parser->error  = error;
 
605
    parser->cursor = cur;
 
606
  }
 
607
 
 
608
 
 
609
  FT_LOCAL_DEF( void )
 
610
  ps_parser_skip_spaces( PS_Parser  parser )
 
611
  {
 
612
    skip_spaces( &parser->cursor, parser->limit );
 
613
  }
 
614
 
 
615
 
 
616
  /* `token' here means either something between balanced delimiters */
 
617
  /* or the next token; the delimiters are not removed.              */
 
618
 
 
619
  FT_LOCAL_DEF( void )
 
620
  ps_parser_to_token( PS_Parser  parser,
 
621
                      T1_Token   token )
 
622
  {
 
623
    FT_Byte*  cur;
 
624
    FT_Byte*  limit;
 
625
    FT_Int    embed;
 
626
 
 
627
 
 
628
    token->type  = T1_TOKEN_TYPE_NONE;
 
629
    token->start = 0;
 
630
    token->limit = 0;
 
631
 
 
632
    /* first of all, skip leading whitespace */
 
633
    ps_parser_skip_spaces( parser );
 
634
 
 
635
    cur   = parser->cursor;
 
636
    limit = parser->limit;
 
637
 
 
638
    if ( cur >= limit )
 
639
      return;
 
640
 
 
641
    switch ( *cur )
 
642
    {
 
643
      /************* check for literal string *****************/
 
644
    case '(':
 
645
      token->type  = T1_TOKEN_TYPE_STRING;
 
646
      token->start = cur;
 
647
 
 
648
      if ( skip_literal_string( &cur, limit ) == PSaux_Err_Ok )
 
649
        token->limit = cur;
 
650
      break;
 
651
 
 
652
      /************* check for programs/array *****************/
 
653
    case '{':
 
654
      token->type  = T1_TOKEN_TYPE_ARRAY;
 
655
      token->start = cur;
 
656
 
 
657
      if ( skip_procedure( &cur, limit ) == PSaux_Err_Ok )
 
658
        token->limit = cur;
 
659
      break;
 
660
 
 
661
      /************* check for table/array ********************/
 
662
      /* XXX: in theory we should also look for "<<"          */
 
663
      /*      since this is semantically equivalent to "[";   */
 
664
      /*      in practice it doesn't matter (?)               */
 
665
    case '[':
 
666
      token->type  = T1_TOKEN_TYPE_ARRAY;
 
667
      embed        = 1;
 
668
      token->start = cur++;
 
669
 
 
670
      /* we need this to catch `[ ]' */
 
671
      parser->cursor = cur;
 
672
      ps_parser_skip_spaces( parser );
 
673
      cur = parser->cursor;
 
674
 
 
675
      while ( cur < limit && !parser->error )
 
676
      {
 
677
        /* XXX: this is wrong because it does not      */
 
678
        /*      skip comments, procedures, and strings */
 
679
        if ( *cur == '[' )
 
680
          embed++;
 
681
        else if ( *cur == ']' )
 
682
        {
 
683
          embed--;
 
684
          if ( embed <= 0 )
 
685
          {
 
686
            token->limit = ++cur;
 
687
            break;
 
688
          }
 
689
        }
 
690
 
 
691
        parser->cursor = cur;
 
692
        ps_parser_skip_PS_token( parser );
 
693
        /* we need this to catch `[XXX ]' */
 
694
        ps_parser_skip_spaces  ( parser );
 
695
        cur = parser->cursor;
 
696
      }
 
697
      break;
 
698
 
 
699
      /* ************ otherwise, it is any token **************/
 
700
    default:
 
701
      token->start = cur;
 
702
      token->type  = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY );
 
703
      ps_parser_skip_PS_token( parser );
 
704
      cur = parser->cursor;
 
705
      if ( !parser->error )
 
706
        token->limit = cur;
 
707
    }
 
708
 
 
709
    if ( !token->limit )
 
710
    {
 
711
      token->start = 0;
 
712
      token->type  = T1_TOKEN_TYPE_NONE;
 
713
    }
 
714
 
 
715
    parser->cursor = cur;
 
716
  }
 
717
 
 
718
 
 
719
  /* NB: `tokens' can be NULL if we only want to count */
 
720
  /* the number of array elements                      */
 
721
 
 
722
  FT_LOCAL_DEF( void )
 
723
  ps_parser_to_token_array( PS_Parser  parser,
 
724
                            T1_Token   tokens,
 
725
                            FT_UInt    max_tokens,
 
726
                            FT_Int*    pnum_tokens )
 
727
  {
 
728
    T1_TokenRec  master;
 
729
 
 
730
 
 
731
    *pnum_tokens = -1;
 
732
 
 
733
    /* this also handles leading whitespace */
 
734
    ps_parser_to_token( parser, &master );
 
735
 
 
736
    if ( master.type == T1_TOKEN_TYPE_ARRAY )
 
737
    {
 
738
      FT_Byte*  old_cursor = parser->cursor;
 
739
      FT_Byte*  old_limit  = parser->limit;
 
740
      T1_Token  cur        = tokens;
 
741
      T1_Token  limit      = cur + max_tokens;
 
742
 
 
743
 
 
744
      /* don't include outermost delimiters */
 
745
      parser->cursor = master.start + 1;
 
746
      parser->limit  = master.limit - 1;
 
747
 
 
748
      while ( parser->cursor < parser->limit )
 
749
      {
 
750
        T1_TokenRec  token;
 
751
 
 
752
 
 
753
        ps_parser_to_token( parser, &token );
 
754
        if ( !token.type )
 
755
          break;
 
756
 
 
757
        if ( tokens != NULL && cur < limit )
 
758
          *cur = token;
 
759
 
 
760
        cur++;
 
761
      }
 
762
 
 
763
      *pnum_tokens = (FT_Int)( cur - tokens );
 
764
 
 
765
      parser->cursor = old_cursor;
 
766
      parser->limit  = old_limit;
 
767
    }
 
768
  }
 
769
 
 
770
 
 
771
  /* first character must be a delimiter or a part of a number */
 
772
  /* NB: `coords' can be NULL if we just want to skip the      */
 
773
  /*     array; in this case we ignore `max_coords'            */
 
774
 
 
775
  static FT_Int
 
776
  ps_tocoordarray( FT_Byte*  *acur,
 
777
                   FT_Byte*   limit,
 
778
                   FT_Int     max_coords,
 
779
                   FT_Short*  coords )
 
780
  {
 
781
    FT_Byte*  cur   = *acur;
 
782
    FT_Int    count = 0;
 
783
    FT_Byte   c, ender;
 
784
 
 
785
 
 
786
    if ( cur >= limit )
 
787
      goto Exit;
 
788
 
 
789
    /* check for the beginning of an array; otherwise, only one number */
 
790
    /* will be read                                                    */
 
791
    c     = *cur;
 
792
    ender = 0;
 
793
 
 
794
    if ( c == '[' )
 
795
      ender = ']';
 
796
    else if ( c == '{' )
 
797
      ender = '}';
 
798
 
 
799
    if ( ender )
 
800
      cur++;
 
801
 
 
802
    /* now, read the coordinates */
 
803
    while ( cur < limit )
 
804
    {
 
805
      FT_Short  dummy;
 
806
      FT_Byte*  old_cur;
 
807
 
 
808
 
 
809
      /* skip whitespace in front of data */
 
810
      skip_spaces( &cur, limit );
 
811
      if ( cur >= limit )
 
812
        goto Exit;
 
813
 
 
814
      if ( *cur == ender )
 
815
      {
 
816
        cur++;
 
817
        break;
 
818
      }
 
819
 
 
820
      old_cur = cur;
 
821
 
 
822
      if ( coords != NULL && count >= max_coords )
 
823
        break;
 
824
 
 
825
      /* call PS_Conv_ToFixed() even if coords == NULL */
 
826
      /* to properly parse number at `cur'             */
 
827
      *( coords != NULL ? &coords[count] : &dummy ) =
 
828
        (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
 
829
 
 
830
      if ( old_cur == cur )
 
831
      {
 
832
        count = -1;
 
833
        goto Exit;
 
834
      }
 
835
      else
 
836
        count++;
 
837
 
 
838
      if ( !ender )
 
839
        break;
 
840
    }
 
841
 
 
842
  Exit:
 
843
    *acur = cur;
 
844
    return count;
 
845
  }
 
846
 
 
847
 
 
848
  /* first character must be a delimiter or a part of a number */
 
849
  /* NB: `values' can be NULL if we just want to skip the      */
 
850
  /*     array; in this case we ignore `max_values'            */
 
851
 
 
852
  static FT_Int
 
853
  ps_tofixedarray( FT_Byte*  *acur,
 
854
                   FT_Byte*   limit,
 
855
                   FT_Int     max_values,
 
856
                   FT_Fixed*  values,
 
857
                   FT_Int     power_ten )
 
858
  {
 
859
    FT_Byte*  cur   = *acur;
 
860
    FT_Int    count = 0;
 
861
    FT_Byte   c, ender;
 
862
 
 
863
 
 
864
    if ( cur >= limit )
 
865
      goto Exit;
 
866
 
 
867
    /* Check for the beginning of an array.  Otherwise, only one number */
 
868
    /* will be read.                                                    */
 
869
    c     = *cur;
 
870
    ender = 0;
 
871
 
 
872
    if ( c == '[' )
 
873
      ender = ']';
 
874
    else if ( c == '{' )
 
875
      ender = '}';
 
876
 
 
877
    if ( ender )
 
878
      cur++;
 
879
 
 
880
    /* now, read the values */
 
881
    while ( cur < limit )
 
882
    {
 
883
      FT_Fixed  dummy;
 
884
      FT_Byte*  old_cur;
 
885
 
 
886
 
 
887
      /* skip whitespace in front of data */
 
888
      skip_spaces( &cur, limit );
 
889
      if ( cur >= limit )
 
890
        goto Exit;
 
891
 
 
892
      if ( *cur == ender )
 
893
      {
 
894
        cur++;
 
895
        break;
 
896
      }
 
897
 
 
898
      old_cur = cur;
 
899
 
 
900
      if ( values != NULL && count >= max_values )
 
901
        break;
 
902
 
 
903
      /* call PS_Conv_ToFixed() even if coords == NULL */
 
904
      /* to properly parse number at `cur'             */
 
905
      *( values != NULL ? &values[count] : &dummy ) =
 
906
        PS_Conv_ToFixed( &cur, limit, power_ten );
 
907
 
 
908
      if ( old_cur == cur )
 
909
      {
 
910
        count = -1;
 
911
        goto Exit;
 
912
      }
 
913
      else
 
914
        count++;
 
915
 
 
916
      if ( !ender )
 
917
        break;
 
918
    }
 
919
 
 
920
  Exit:
 
921
    *acur = cur;
 
922
    return count;
 
923
  }
 
924
 
 
925
 
 
926
#if 0
 
927
 
 
928
  static FT_String*
 
929
  ps_tostring( FT_Byte**  cursor,
 
930
               FT_Byte*   limit,
 
931
               FT_Memory  memory )
 
932
  {
 
933
    FT_Byte*    cur = *cursor;
 
934
    FT_PtrDist  len = 0;
 
935
    FT_Int      count;
 
936
    FT_String*  result;
 
937
    FT_Error    error;
 
938
 
 
939
 
 
940
    /* XXX: some stupid fonts have a `Notice' or `Copyright' string     */
 
941
    /*      that simply doesn't begin with an opening parenthesis, even */
 
942
    /*      though they have a closing one!  E.g. "amuncial.pfb"        */
 
943
    /*                                                                  */
 
944
    /*      We must deal with these ill-fated cases there.  Note that   */
 
945
    /*      these fonts didn't work with the old Type 1 driver as the   */
 
946
    /*      notice/copyright was not recognized as a valid string token */
 
947
    /*      and made the old token parser commit errors.                */
 
948
 
 
949
    while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
 
950
      cur++;
 
951
    if ( cur + 1 >= limit )
 
952
      return 0;
 
953
 
 
954
    if ( *cur == '(' )
 
955
      cur++;  /* skip the opening parenthesis, if there is one */
 
956
 
 
957
    *cursor = cur;
 
958
    count   = 0;
 
959
 
 
960
    /* then, count its length */
 
961
    for ( ; cur < limit; cur++ )
 
962
    {
 
963
      if ( *cur == '(' )
 
964
        count++;
 
965
 
 
966
      else if ( *cur == ')' )
 
967
      {
 
968
        count--;
 
969
        if ( count < 0 )
 
970
          break;
 
971
      }
 
972
    }
 
973
 
 
974
    len = cur - *cursor;
 
975
    if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
 
976
      return 0;
 
977
 
 
978
    /* now copy the string */
 
979
    FT_MEM_COPY( result, *cursor, len );
 
980
    result[len] = '\0';
 
981
    *cursor = cur;
 
982
    return result;
 
983
  }
 
984
 
 
985
#endif /* 0 */
 
986
 
 
987
 
 
988
  static int
 
989
  ps_tobool( FT_Byte*  *acur,
 
990
             FT_Byte*   limit )
 
991
  {
 
992
    FT_Byte*  cur    = *acur;
 
993
    FT_Bool   result = 0;
 
994
 
 
995
 
 
996
    /* return 1 if we find `true', 0 otherwise */
 
997
    if ( cur + 3 < limit &&
 
998
         cur[0] == 't'   &&
 
999
         cur[1] == 'r'   &&
 
1000
         cur[2] == 'u'   &&
 
1001
         cur[3] == 'e'   )
 
1002
    {
 
1003
      result = 1;
 
1004
      cur   += 5;
 
1005
    }
 
1006
    else if ( cur + 4 < limit &&
 
1007
              cur[0] == 'f'   &&
 
1008
              cur[1] == 'a'   &&
 
1009
              cur[2] == 'l'   &&
 
1010
              cur[3] == 's'   &&
 
1011
              cur[4] == 'e'   )
 
1012
    {
 
1013
      result = 0;
 
1014
      cur   += 6;
 
1015
    }
 
1016
 
 
1017
    *acur = cur;
 
1018
    return result;
 
1019
  }
 
1020
 
 
1021
 
 
1022
  /* load a simple field (i.e. non-table) into the current list of objects */
 
1023
 
 
1024
  FT_LOCAL_DEF( FT_Error )
 
1025
  ps_parser_load_field( PS_Parser       parser,
 
1026
                        const T1_Field  field,
 
1027
                        void**          objects,
 
1028
                        FT_UInt         max_objects,
 
1029
                        FT_ULong*       pflags )
 
1030
  {
 
1031
    T1_TokenRec  token;
 
1032
    FT_Byte*     cur;
 
1033
    FT_Byte*     limit;
 
1034
    FT_UInt      count;
 
1035
    FT_UInt      idx;
 
1036
    FT_Error     error;
 
1037
 
 
1038
 
 
1039
    /* this also skips leading whitespace */
 
1040
    ps_parser_to_token( parser, &token );
 
1041
    if ( !token.type )
 
1042
      goto Fail;
 
1043
 
 
1044
    count = 1;
 
1045
    idx   = 0;
 
1046
    cur   = token.start;
 
1047
    limit = token.limit;
 
1048
 
 
1049
    /* we must detect arrays in /FontBBox */
 
1050
    if ( field->type == T1_FIELD_TYPE_BBOX )
 
1051
    {
 
1052
      T1_TokenRec  token2;
 
1053
      FT_Byte*     old_cur   = parser->cursor;
 
1054
      FT_Byte*     old_limit = parser->limit;
 
1055
 
 
1056
 
 
1057
      /* don't include delimiters */
 
1058
      parser->cursor = token.start + 1;
 
1059
      parser->limit  = token.limit - 1;
 
1060
 
 
1061
      ps_parser_to_token( parser, &token2 );
 
1062
      parser->cursor = old_cur;
 
1063
      parser->limit  = old_limit;
 
1064
 
 
1065
      if ( token2.type == T1_TOKEN_TYPE_ARRAY )
 
1066
        goto FieldArray;
 
1067
    }
 
1068
    else if ( token.type == T1_TOKEN_TYPE_ARRAY )
 
1069
    {
 
1070
    FieldArray:
 
1071
      /* if this is an array and we have no blend, an error occurs */
 
1072
      if ( max_objects == 0 )
 
1073
        goto Fail;
 
1074
 
 
1075
      count = max_objects;
 
1076
      idx   = 1;
 
1077
 
 
1078
      /* don't include delimiters */
 
1079
      cur++;
 
1080
      limit--;
 
1081
    }
 
1082
 
 
1083
    for ( ; count > 0; count--, idx++ )
 
1084
    {
 
1085
      FT_Byte*    q = (FT_Byte*)objects[idx] + field->offset;
 
1086
      FT_Long     val;
 
1087
      FT_String*  string;
 
1088
 
 
1089
 
 
1090
      skip_spaces( &cur, limit );
 
1091
 
 
1092
      switch ( field->type )
 
1093
      {
 
1094
      case T1_FIELD_TYPE_BOOL:
 
1095
        val = ps_tobool( &cur, limit );
 
1096
        goto Store_Integer;
 
1097
 
 
1098
      case T1_FIELD_TYPE_FIXED:
 
1099
        val = PS_Conv_ToFixed( &cur, limit, 0 );
 
1100
        goto Store_Integer;
 
1101
 
 
1102
      case T1_FIELD_TYPE_FIXED_1000:
 
1103
        val = PS_Conv_ToFixed( &cur, limit, 3 );
 
1104
        goto Store_Integer;
 
1105
 
 
1106
      case T1_FIELD_TYPE_INTEGER:
 
1107
        val = PS_Conv_ToInt( &cur, limit );
 
1108
        /* fall through */
 
1109
 
 
1110
      Store_Integer:
 
1111
        switch ( field->size )
 
1112
        {
 
1113
        case (8 / FT_CHAR_BIT):
 
1114
          *(FT_Byte*)q = (FT_Byte)val;
 
1115
          break;
 
1116
 
 
1117
        case (16 / FT_CHAR_BIT):
 
1118
          *(FT_UShort*)q = (FT_UShort)val;
 
1119
          break;
 
1120
 
 
1121
        case (32 / FT_CHAR_BIT):
 
1122
          *(FT_UInt32*)q = (FT_UInt32)val;
 
1123
          break;
 
1124
 
 
1125
        default:                /* for 64-bit systems */
 
1126
          *(FT_Long*)q = val;
 
1127
        }
 
1128
        break;
 
1129
 
 
1130
      case T1_FIELD_TYPE_STRING:
 
1131
      case T1_FIELD_TYPE_KEY:
 
1132
        {
 
1133
          FT_Memory  memory = parser->memory;
 
1134
          FT_UInt    len    = (FT_UInt)( limit - cur );
 
1135
 
 
1136
 
 
1137
          if ( cur >= limit )
 
1138
            break;
 
1139
 
 
1140
          /* we allow both a string or a name   */
 
1141
          /* for cases like /FontName (foo) def */
 
1142
          if ( token.type == T1_TOKEN_TYPE_KEY )
 
1143
          {
 
1144
            /* don't include leading `/' */
 
1145
            len--;
 
1146
            cur++;
 
1147
          }
 
1148
          else if ( token.type == T1_TOKEN_TYPE_STRING )
 
1149
          {
 
1150
            /* don't include delimiting parentheses    */
 
1151
            /* XXX we don't handle <<...>> here        */
 
1152
            /* XXX should we convert octal escapes?    */
 
1153
            /*     if so, what encoding should we use? */
 
1154
            cur++;
 
1155
            len -= 2;
 
1156
          }
 
1157
          else
 
1158
          {
 
1159
            FT_ERROR(( "ps_parser_load_field:"
 
1160
                       " expected a name or string\n"
 
1161
                       "                     "
 
1162
                       " but found token of type %d instead\n",
 
1163
                       token.type ));
 
1164
            error = PSaux_Err_Invalid_File_Format;
 
1165
            goto Exit;
 
1166
          }
 
1167
 
 
1168
          /* for this to work (FT_String**)q must have been */
 
1169
          /* initialized to NULL                            */
 
1170
          if ( *(FT_String**)q != NULL )
 
1171
          {
 
1172
            FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
 
1173
                        field->ident ));
 
1174
            FT_FREE( *(FT_String**)q );
 
1175
            *(FT_String**)q = NULL;
 
1176
          }
 
1177
 
 
1178
          if ( FT_ALLOC( string, len + 1 ) )
 
1179
            goto Exit;
 
1180
 
 
1181
          FT_MEM_COPY( string, cur, len );
 
1182
          string[len] = 0;
 
1183
 
 
1184
          *(FT_String**)q = string;
 
1185
        }
 
1186
        break;
 
1187
 
 
1188
      case T1_FIELD_TYPE_BBOX:
 
1189
        {
 
1190
          FT_Fixed  temp[4];
 
1191
          FT_BBox*  bbox = (FT_BBox*)q;
 
1192
          FT_Int    result;
 
1193
 
 
1194
 
 
1195
          result = ps_tofixedarray( &cur, limit, 4, temp, 0 );
 
1196
 
 
1197
          if ( result < 0 )
 
1198
          {
 
1199
            FT_ERROR(( "ps_parser_load_field:"
 
1200
                       " expected four integers in bounding box\n" ));
 
1201
            error = PSaux_Err_Invalid_File_Format;
 
1202
            goto Exit;
 
1203
          }
 
1204
 
 
1205
          bbox->xMin = FT_RoundFix( temp[0] );
 
1206
          bbox->yMin = FT_RoundFix( temp[1] );
 
1207
          bbox->xMax = FT_RoundFix( temp[2] );
 
1208
          bbox->yMax = FT_RoundFix( temp[3] );
 
1209
        }
 
1210
        break;
 
1211
 
 
1212
      default:
 
1213
        /* an error occurred */
 
1214
        goto Fail;
 
1215
      }
 
1216
    }
 
1217
 
 
1218
#if 0  /* obsolete -- keep for reference */
 
1219
    if ( pflags )
 
1220
      *pflags |= 1L << field->flag_bit;
 
1221
#else
 
1222
    FT_UNUSED( pflags );
 
1223
#endif
 
1224
 
 
1225
    error = PSaux_Err_Ok;
 
1226
 
 
1227
  Exit:
 
1228
    return error;
 
1229
 
 
1230
  Fail:
 
1231
    error = PSaux_Err_Invalid_File_Format;
 
1232
    goto Exit;
 
1233
  }
 
1234
 
 
1235
 
 
1236
#define T1_MAX_TABLE_ELEMENTS  32
 
1237
 
 
1238
 
 
1239
  FT_LOCAL_DEF( FT_Error )
 
1240
  ps_parser_load_field_table( PS_Parser       parser,
 
1241
                              const T1_Field  field,
 
1242
                              void**          objects,
 
1243
                              FT_UInt         max_objects,
 
1244
                              FT_ULong*       pflags )
 
1245
  {
 
1246
    T1_TokenRec  elements[T1_MAX_TABLE_ELEMENTS];
 
1247
    T1_Token     token;
 
1248
    FT_Int       num_elements;
 
1249
    FT_Error     error = PSaux_Err_Ok;
 
1250
    FT_Byte*     old_cursor;
 
1251
    FT_Byte*     old_limit;
 
1252
    T1_FieldRec  fieldrec = *(T1_Field)field;
 
1253
 
 
1254
 
 
1255
    fieldrec.type = T1_FIELD_TYPE_INTEGER;
 
1256
    if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
 
1257
         field->type == T1_FIELD_TYPE_BBOX        )
 
1258
      fieldrec.type = T1_FIELD_TYPE_FIXED;
 
1259
 
 
1260
    ps_parser_to_token_array( parser, elements,
 
1261
                              T1_MAX_TABLE_ELEMENTS, &num_elements );
 
1262
    if ( num_elements < 0 )
 
1263
    {
 
1264
      error = PSaux_Err_Ignore;
 
1265
      goto Exit;
 
1266
    }
 
1267
    if ( (FT_UInt)num_elements > field->array_max )
 
1268
      num_elements = field->array_max;
 
1269
 
 
1270
    old_cursor = parser->cursor;
 
1271
    old_limit  = parser->limit;
 
1272
 
 
1273
    /* we store the elements count if necessary;           */
 
1274
    /* we further assume that `count_offset' can't be zero */
 
1275
    if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 )
 
1276
      *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
 
1277
        (FT_Byte)num_elements;
 
1278
 
 
1279
    /* we now load each element, adjusting the field.offset on each one */
 
1280
    token = elements;
 
1281
    for ( ; num_elements > 0; num_elements--, token++ )
 
1282
    {
 
1283
      parser->cursor = token->start;
 
1284
      parser->limit  = token->limit;
 
1285
      ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
 
1286
      fieldrec.offset += fieldrec.size;
 
1287
    }
 
1288
 
 
1289
#if 0  /* obsolete -- keep for reference */
 
1290
    if ( pflags )
 
1291
      *pflags |= 1L << field->flag_bit;
 
1292
#else
 
1293
    FT_UNUSED( pflags );
 
1294
#endif
 
1295
 
 
1296
    parser->cursor = old_cursor;
 
1297
    parser->limit  = old_limit;
 
1298
 
 
1299
  Exit:
 
1300
    return error;
 
1301
  }
 
1302
 
 
1303
 
 
1304
  FT_LOCAL_DEF( FT_Long )
 
1305
  ps_parser_to_int( PS_Parser  parser )
 
1306
  {
 
1307
    ps_parser_skip_spaces( parser );
 
1308
    return PS_Conv_ToInt( &parser->cursor, parser->limit );
 
1309
  }
 
1310
 
 
1311
 
 
1312
  /* first character must be `<' if `delimiters' is non-zero */
 
1313
 
 
1314
  FT_LOCAL_DEF( FT_Error )
 
1315
  ps_parser_to_bytes( PS_Parser  parser,
 
1316
                      FT_Byte*   bytes,
 
1317
                      FT_Offset  max_bytes,
 
1318
                      FT_Long*   pnum_bytes,
 
1319
                      FT_Bool    delimiters )
 
1320
  {
 
1321
    FT_Error  error = PSaux_Err_Ok;
 
1322
    FT_Byte*  cur;
 
1323
 
 
1324
 
 
1325
    ps_parser_skip_spaces( parser );
 
1326
    cur = parser->cursor;
 
1327
 
 
1328
    if ( cur >= parser->limit )
 
1329
      goto Exit;
 
1330
 
 
1331
    if ( delimiters )
 
1332
    {
 
1333
      if ( *cur != '<' )
 
1334
      {
 
1335
        FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
 
1336
        error = PSaux_Err_Invalid_File_Format;
 
1337
        goto Exit;
 
1338
      }
 
1339
 
 
1340
      cur++;
 
1341
    }
 
1342
 
 
1343
    *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
 
1344
                                          parser->limit,
 
1345
                                          bytes,
 
1346
                                          max_bytes );
 
1347
 
 
1348
    if ( delimiters )
 
1349
    {
 
1350
      if ( cur < parser->limit && *cur != '>' )
 
1351
      {
 
1352
        FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
 
1353
        error = PSaux_Err_Invalid_File_Format;
 
1354
        goto Exit;
 
1355
      }
 
1356
 
 
1357
      cur++;
 
1358
    }
 
1359
 
 
1360
    parser->cursor = cur;
 
1361
 
 
1362
  Exit:
 
1363
    return error;
 
1364
  }
 
1365
 
 
1366
 
 
1367
  FT_LOCAL_DEF( FT_Fixed )
 
1368
  ps_parser_to_fixed( PS_Parser  parser,
 
1369
                      FT_Int     power_ten )
 
1370
  {
 
1371
    ps_parser_skip_spaces( parser );
 
1372
    return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
 
1373
  }
 
1374
 
 
1375
 
 
1376
  FT_LOCAL_DEF( FT_Int )
 
1377
  ps_parser_to_coord_array( PS_Parser  parser,
 
1378
                            FT_Int     max_coords,
 
1379
                            FT_Short*  coords )
 
1380
  {
 
1381
    ps_parser_skip_spaces( parser );
 
1382
    return ps_tocoordarray( &parser->cursor, parser->limit,
 
1383
                            max_coords, coords );
 
1384
  }
 
1385
 
 
1386
 
 
1387
  FT_LOCAL_DEF( FT_Int )
 
1388
  ps_parser_to_fixed_array( PS_Parser  parser,
 
1389
                            FT_Int     max_values,
 
1390
                            FT_Fixed*  values,
 
1391
                            FT_Int     power_ten )
 
1392
  {
 
1393
    ps_parser_skip_spaces( parser );
 
1394
    return ps_tofixedarray( &parser->cursor, parser->limit,
 
1395
                            max_values, values, power_ten );
 
1396
  }
 
1397
 
 
1398
 
 
1399
#if 0
 
1400
 
 
1401
  FT_LOCAL_DEF( FT_String* )
 
1402
  T1_ToString( PS_Parser  parser )
 
1403
  {
 
1404
    return ps_tostring( &parser->cursor, parser->limit, parser->memory );
 
1405
  }
 
1406
 
 
1407
 
 
1408
  FT_LOCAL_DEF( FT_Bool )
 
1409
  T1_ToBool( PS_Parser  parser )
 
1410
  {
 
1411
    return ps_tobool( &parser->cursor, parser->limit );
 
1412
  }
 
1413
 
 
1414
#endif /* 0 */
 
1415
 
 
1416
 
 
1417
  FT_LOCAL_DEF( void )
 
1418
  ps_parser_init( PS_Parser  parser,
 
1419
                  FT_Byte*   base,
 
1420
                  FT_Byte*   limit,
 
1421
                  FT_Memory  memory )
 
1422
  {
 
1423
    parser->error  = PSaux_Err_Ok;
 
1424
    parser->base   = base;
 
1425
    parser->limit  = limit;
 
1426
    parser->cursor = base;
 
1427
    parser->memory = memory;
 
1428
    parser->funcs  = ps_parser_funcs;
 
1429
  }
 
1430
 
 
1431
 
 
1432
  FT_LOCAL_DEF( void )
 
1433
  ps_parser_done( PS_Parser  parser )
 
1434
  {
 
1435
    FT_UNUSED( parser );
 
1436
  }
 
1437
 
 
1438
 
 
1439
  /*************************************************************************/
 
1440
  /*************************************************************************/
 
1441
  /*****                                                               *****/
 
1442
  /*****                            T1 BUILDER                         *****/
 
1443
  /*****                                                               *****/
 
1444
  /*************************************************************************/
 
1445
  /*************************************************************************/
 
1446
 
 
1447
  /*************************************************************************/
 
1448
  /*                                                                       */
 
1449
  /* <Function>                                                            */
 
1450
  /*    t1_builder_init                                                    */
 
1451
  /*                                                                       */
 
1452
  /* <Description>                                                         */
 
1453
  /*    Initializes a given glyph builder.                                 */
 
1454
  /*                                                                       */
 
1455
  /* <InOut>                                                               */
 
1456
  /*    builder :: A pointer to the glyph builder to initialize.           */
 
1457
  /*                                                                       */
 
1458
  /* <Input>                                                               */
 
1459
  /*    face    :: The current face object.                                */
 
1460
  /*                                                                       */
 
1461
  /*    size    :: The current size object.                                */
 
1462
  /*                                                                       */
 
1463
  /*    glyph   :: The current glyph object.                               */
 
1464
  /*                                                                       */
 
1465
  /*    hinting :: Whether hinting should be applied.                      */
 
1466
  /*                                                                       */
 
1467
  FT_LOCAL_DEF( void )
 
1468
  t1_builder_init( T1_Builder    builder,
 
1469
                   FT_Face       face,
 
1470
                   FT_Size       size,
 
1471
                   FT_GlyphSlot  glyph,
 
1472
                   FT_Bool       hinting )
 
1473
  {
 
1474
    builder->parse_state = T1_Parse_Start;
 
1475
    builder->load_points = 1;
 
1476
 
 
1477
    builder->face   = face;
 
1478
    builder->glyph  = glyph;
 
1479
    builder->memory = face->memory;
 
1480
 
 
1481
    if ( glyph )
 
1482
    {
 
1483
      FT_GlyphLoader  loader = glyph->internal->loader;
 
1484
 
 
1485
 
 
1486
      builder->loader  = loader;
 
1487
      builder->base    = &loader->base.outline;
 
1488
      builder->current = &loader->current.outline;
 
1489
      FT_GlyphLoader_Rewind( loader );
 
1490
 
 
1491
      builder->hints_globals = size->internal;
 
1492
      builder->hints_funcs   = 0;
 
1493
 
 
1494
      if ( hinting )
 
1495
        builder->hints_funcs = glyph->internal->glyph_hints;
 
1496
    }
 
1497
 
 
1498
    builder->pos_x = 0;
 
1499
    builder->pos_y = 0;
 
1500
 
 
1501
    builder->left_bearing.x = 0;
 
1502
    builder->left_bearing.y = 0;
 
1503
    builder->advance.x      = 0;
 
1504
    builder->advance.y      = 0;
 
1505
 
 
1506
    builder->funcs = t1_builder_funcs;
 
1507
  }
 
1508
 
 
1509
 
 
1510
  /*************************************************************************/
 
1511
  /*                                                                       */
 
1512
  /* <Function>                                                            */
 
1513
  /*    t1_builder_done                                                    */
 
1514
  /*                                                                       */
 
1515
  /* <Description>                                                         */
 
1516
  /*    Finalizes a given glyph builder.  Its contents can still be used   */
 
1517
  /*    after the call, but the function saves important information       */
 
1518
  /*    within the corresponding glyph slot.                               */
 
1519
  /*                                                                       */
 
1520
  /* <Input>                                                               */
 
1521
  /*    builder :: A pointer to the glyph builder to finalize.             */
 
1522
  /*                                                                       */
 
1523
  FT_LOCAL_DEF( void )
 
1524
  t1_builder_done( T1_Builder  builder )
 
1525
  {
 
1526
    FT_GlyphSlot  glyph = builder->glyph;
 
1527
 
 
1528
 
 
1529
    if ( glyph )
 
1530
      glyph->outline = *builder->base;
 
1531
  }
 
1532
 
 
1533
 
 
1534
  /* check that there is enough space for `count' more points */
 
1535
  FT_LOCAL_DEF( FT_Error )
 
1536
  t1_builder_check_points( T1_Builder  builder,
 
1537
                           FT_Int      count )
 
1538
  {
 
1539
    return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
 
1540
  }
 
1541
 
 
1542
 
 
1543
  /* add a new point, do not check space */
 
1544
  FT_LOCAL_DEF( void )
 
1545
  t1_builder_add_point( T1_Builder  builder,
 
1546
                        FT_Pos      x,
 
1547
                        FT_Pos      y,
 
1548
                        FT_Byte     flag )
 
1549
  {
 
1550
    FT_Outline*  outline = builder->current;
 
1551
 
 
1552
 
 
1553
    if ( builder->load_points )
 
1554
    {
 
1555
      FT_Vector*  point   = outline->points + outline->n_points;
 
1556
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
 
1557
 
 
1558
 
 
1559
      point->x = FIXED_TO_INT( x );
 
1560
      point->y = FIXED_TO_INT( y );
 
1561
      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
 
1562
    }
 
1563
    outline->n_points++;
 
1564
  }
 
1565
 
 
1566
 
 
1567
  /* check space for a new on-curve point, then add it */
 
1568
  FT_LOCAL_DEF( FT_Error )
 
1569
  t1_builder_add_point1( T1_Builder  builder,
 
1570
                         FT_Pos      x,
 
1571
                         FT_Pos      y )
 
1572
  {
 
1573
    FT_Error  error;
 
1574
 
 
1575
 
 
1576
    error = t1_builder_check_points( builder, 1 );
 
1577
    if ( !error )
 
1578
      t1_builder_add_point( builder, x, y, 1 );
 
1579
 
 
1580
    return error;
 
1581
  }
 
1582
 
 
1583
 
 
1584
  /* check space for a new contour, then add it */
 
1585
  FT_LOCAL_DEF( FT_Error )
 
1586
  t1_builder_add_contour( T1_Builder  builder )
 
1587
  {
 
1588
    FT_Outline*  outline = builder->current;
 
1589
    FT_Error     error;
 
1590
 
 
1591
 
 
1592
    /* this might happen in invalid fonts */
 
1593
    if ( !outline )
 
1594
    {
 
1595
      FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" ));
 
1596
      return PSaux_Err_Invalid_File_Format;
 
1597
    }
 
1598
 
 
1599
    if ( !builder->load_points )
 
1600
    {
 
1601
      outline->n_contours++;
 
1602
      return PSaux_Err_Ok;
 
1603
    }
 
1604
 
 
1605
    error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
 
1606
    if ( !error )
 
1607
    {
 
1608
      if ( outline->n_contours > 0 )
 
1609
        outline->contours[outline->n_contours - 1] =
 
1610
          (short)( outline->n_points - 1 );
 
1611
 
 
1612
      outline->n_contours++;
 
1613
    }
 
1614
 
 
1615
    return error;
 
1616
  }
 
1617
 
 
1618
 
 
1619
  /* if a path was begun, add its first on-curve point */
 
1620
  FT_LOCAL_DEF( FT_Error )
 
1621
  t1_builder_start_point( T1_Builder  builder,
 
1622
                          FT_Pos      x,
 
1623
                          FT_Pos      y )
 
1624
  {
 
1625
    FT_Error  error = PSaux_Err_Invalid_File_Format;
 
1626
 
 
1627
 
 
1628
    /* test whether we are building a new contour */
 
1629
 
 
1630
    if ( builder->parse_state == T1_Parse_Have_Path )
 
1631
      error = PSaux_Err_Ok;
 
1632
    else
 
1633
    {
 
1634
      builder->parse_state = T1_Parse_Have_Path;
 
1635
      error = t1_builder_add_contour( builder );
 
1636
      if ( !error )
 
1637
        error = t1_builder_add_point1( builder, x, y );
 
1638
    }
 
1639
 
 
1640
    return error;
 
1641
  }
 
1642
 
 
1643
 
 
1644
  /* close the current contour */
 
1645
  FT_LOCAL_DEF( void )
 
1646
  t1_builder_close_contour( T1_Builder  builder )
 
1647
  {
 
1648
    FT_Outline*  outline = builder->current;
 
1649
    FT_Int       first;
 
1650
 
 
1651
 
 
1652
    if ( !outline )
 
1653
      return;
 
1654
 
 
1655
    first = outline->n_contours <= 1
 
1656
            ? 0 : outline->contours[outline->n_contours - 2] + 1;
 
1657
 
 
1658
    /* We must not include the last point in the path if it */
 
1659
    /* is located on the first point.                       */
 
1660
    if ( outline->n_points > 1 )
 
1661
    {
 
1662
      FT_Vector*  p1      = outline->points + first;
 
1663
      FT_Vector*  p2      = outline->points + outline->n_points - 1;
 
1664
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
 
1665
 
 
1666
 
 
1667
      /* `delete' last point only if it coincides with the first */
 
1668
      /* point and it is not a control point (which can happen). */
 
1669
      if ( p1->x == p2->x && p1->y == p2->y )
 
1670
        if ( *control == FT_CURVE_TAG_ON )
 
1671
          outline->n_points--;
 
1672
    }
 
1673
 
 
1674
    if ( outline->n_contours > 0 )
 
1675
    {
 
1676
      /* Don't add contours only consisting of one point, i.e.,  */
 
1677
      /* check whether the first and the last point is the same. */
 
1678
      if ( first == outline->n_points - 1 )
 
1679
      {
 
1680
        outline->n_contours--;
 
1681
        outline->n_points--;
 
1682
      }
 
1683
      else
 
1684
        outline->contours[outline->n_contours - 1] =
 
1685
          (short)( outline->n_points - 1 );
 
1686
    }
 
1687
  }
 
1688
 
 
1689
 
 
1690
  /*************************************************************************/
 
1691
  /*************************************************************************/
 
1692
  /*****                                                               *****/
 
1693
  /*****                            OTHER                              *****/
 
1694
  /*****                                                               *****/
 
1695
  /*************************************************************************/
 
1696
  /*************************************************************************/
 
1697
 
 
1698
  FT_LOCAL_DEF( void )
 
1699
  t1_decrypt( FT_Byte*   buffer,
 
1700
              FT_Offset  length,
 
1701
              FT_UShort  seed )
 
1702
  {
 
1703
    PS_Conv_EexecDecode( &buffer,
 
1704
                         buffer + length,
 
1705
                         buffer,
 
1706
                         length,
 
1707
                         &seed );
 
1708
  }
 
1709
 
 
1710
 
 
1711
/* END */