~ubuntu-branches/ubuntu/wily/hedgewars/wily

« back to all changes in this revision

Viewing changes to misc/libfreetype/src/psaux/psobjs.c

  • Committer: Package Import Robot
  • Author(s): Dmitry E. Oboukhov
  • Date: 2011-09-23 10:16:55 UTC
  • mfrom: (1.2.11 upstream)
  • Revision ID: package-import@ubuntu.com-20110923101655-3977th2gc5n0a3pv
Tags: 0.9.16-1
* New upstream version.
 + Downloadable content! Simply click to install any content.
   New voices, hats, maps, themes, translations, music, scripts...
   Hedgewars is now more customisable than ever before! As time goes
   by we will be soliciting community content to feature on this page,
   so remember to check it from time to time. If you decide you want
   to go back to standard Hedgewars, just remove the Data directory
   from your Hedgewars config directory.
 + 3-D rendering! Diorama-like rendering of the game in a variety
   of 3D modes. Let us know which ones work best for you, we didn't
   really have the equipment to test them all.
 + Resizable game window.
 + New utilities! The Time Box will remove one of your hedgehogs
   from the game for a while, protecting from attack until it returns,
   somewhere else on the map. Land spray will allow you to build bridges,
   seal up holes, or just make life unpleasant for your enemies.
 + New single player: Bamboo Thicket, That Sinking Feeling, Newton and
   the Tree and multi-player: The Specialists, Space Invaders,
   Racer - scripts! And a ton more script hooks for scripters
 + New twists on old weapons. Drill strike, seduction and fire have
   been adjusted. Defective mines have been added, rope can attach to
   hogs/crates/barrels again, grenades now have variable bounce (use
   precise key + 1-5). Portal gun is now more usable in flight and
   all game actions are a lot faster.
 + New theme - Golf, dozens of new community hats and a new
   localised Default voice, Ukranian.

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