~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/3rdparty/freetype/src/psaux/psobjs.c

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

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