Coverage Report

Created: 2021-08-22 09:07

/src/skia/third_party/externals/freetype/src/psaux/psobjs.c
Line
Count
Source (jump to first uncovered line)
1
/****************************************************************************
2
 *
3
 * psobjs.c
4
 *
5
 *   Auxiliary functions for PostScript fonts (body).
6
 *
7
 * Copyright (C) 1996-2021 by
8
 * David Turner, Robert Wilhelm, and Werner Lemberg.
9
 *
10
 * This file is part of the FreeType project, and may only be used,
11
 * modified, and distributed under the terms of the FreeType project
12
 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
13
 * this file you indicate that you have read the license and
14
 * understand and accept it fully.
15
 *
16
 */
17
18
19
#include <freetype/internal/psaux.h>
20
#include <freetype/internal/ftdebug.h>
21
#include <freetype/internal/ftcalc.h>
22
#include <freetype/ftdriver.h>
23
24
#include "psobjs.h"
25
#include "psconv.h"
26
27
#include "psauxerr.h"
28
#include "psauxmod.h"
29
30
31
  /**************************************************************************
32
   *
33
   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
34
   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
35
   * messages during execution.
36
   */
37
#undef  FT_COMPONENT
38
#define FT_COMPONENT  psobjs
39
40
41
  /*************************************************************************/
42
  /*************************************************************************/
43
  /*****                                                               *****/
44
  /*****                             PS_TABLE                          *****/
45
  /*****                                                               *****/
46
  /*************************************************************************/
47
  /*************************************************************************/
48
49
  /**************************************************************************
50
   *
51
   * @Function:
52
   *   ps_table_new
53
   *
54
   * @Description:
55
   *   Initializes a PS_Table.
56
   *
57
   * @InOut:
58
   *   table ::
59
   *     The address of the target table.
60
   *
61
   * @Input:
62
   *   count ::
63
   *     The table size = the maximum number of elements.
64
   *
65
   *   memory ::
66
   *     The memory object to use for all subsequent
67
   *     reallocations.
68
   *
69
   * @Return:
70
   *   FreeType error code.  0 means success.
71
   */
72
  FT_LOCAL_DEF( FT_Error )
73
  ps_table_new( PS_Table   table,
74
                FT_Int     count,
75
                FT_Memory  memory )
76
0
  {
77
0
    FT_Error  error;
78
79
80
0
    table->memory = memory;
81
0
    if ( FT_NEW_ARRAY( table->elements, count ) ||
82
0
         FT_NEW_ARRAY( table->lengths,  count ) )
83
0
      goto Exit;
84
85
0
    table->max_elems = count;
86
0
    table->init      = 0xDEADBEEFUL;
87
0
    table->num_elems = 0;
88
0
    table->block     = NULL;
89
0
    table->capacity  = 0;
90
0
    table->cursor    = 0;
91
92
0
    *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs;
93
94
0
  Exit:
95
0
    if ( error )
96
0
      FT_FREE( table->elements );
97
98
0
    return error;
99
0
  }
100
101
102
  static void
103
  shift_elements( PS_Table  table,
104
                  FT_Byte*  old_base )
105
0
  {
106
0
    FT_PtrDist  delta  = table->block - old_base;
107
0
    FT_Byte**   offset = table->elements;
108
0
    FT_Byte**   limit  = offset + table->max_elems;
109
110
111
0
    for ( ; offset < limit; offset++ )
112
0
    {
113
0
      if ( offset[0] )
114
0
        offset[0] += delta;
115
0
    }
116
0
  }
117
118
119
  static FT_Error
120
  reallocate_t1_table( PS_Table   table,
121
                       FT_Offset  new_size )
122
0
  {
123
0
    FT_Memory  memory   = table->memory;
124
0
    FT_Byte*   old_base = table->block;
125
0
    FT_Error   error;
126
127
128
    /* allocate new base block */
129
0
    if ( FT_ALLOC( table->block, new_size ) )
130
0
    {
131
0
      table->block = old_base;
132
0
      return error;
133
0
    }
134
135
    /* copy elements and shift offsets */
136
0
    if ( old_base )
137
0
    {
138
0
      FT_MEM_COPY( table->block, old_base, table->capacity );
139
0
      shift_elements( table, old_base );
140
0
      FT_FREE( old_base );
141
0
    }
142
143
0
    table->capacity = new_size;
144
145
0
    return FT_Err_Ok;
146
0
  }
147
148
149
  /**************************************************************************
150
   *
151
   * @Function:
152
   *   ps_table_add
153
   *
154
   * @Description:
155
   *   Adds an object to a PS_Table, possibly growing its memory block.
156
   *
157
   * @InOut:
158
   *   table ::
159
   *     The target table.
160
   *
161
   * @Input:
162
   *   idx ::
163
   *     The index of the object in the table.
164
   *
165
   *   object ::
166
   *     The address of the object to copy in memory.
167
   *
168
   *   length ::
169
   *     The length in bytes of the source object.
170
   *
171
   * @Return:
172
   *   FreeType error code.  0 means success.  An error is returned if a
173
   *   reallocation fails.
174
   */
175
  FT_LOCAL_DEF( FT_Error )
176
  ps_table_add( PS_Table     table,
177
                FT_Int       idx,
178
                const void*  object,
179
                FT_UInt      length )
180
0
  {
181
0
    if ( idx < 0 || idx >= table->max_elems )
182
0
    {
183
0
      FT_ERROR(( "ps_table_add: invalid index\n" ));
184
0
      return FT_THROW( Invalid_Argument );
185
0
    }
186
187
    /* grow the base block if needed */
188
0
    if ( table->cursor + length > table->capacity )
189
0
    {
190
0
      FT_Error    error;
191
0
      FT_Offset   new_size = table->capacity;
192
0
      FT_PtrDist  in_offset;
193
194
195
0
      in_offset = (FT_Byte*)object - table->block;
196
0
      if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity )
197
0
        in_offset = -1;
198
199
0
      while ( new_size < table->cursor + length )
200
0
      {
201
        /* increase size by 25% and round up to the nearest multiple
202
           of 1024 */
203
0
        new_size += ( new_size >> 2 ) + 1;
204
0
        new_size  = FT_PAD_CEIL( new_size, 1024 );
205
0
      }
206
207
0
      error = reallocate_t1_table( table, new_size );
208
0
      if ( error )
209
0
        return error;
210
211
0
      if ( in_offset >= 0 )
212
0
        object = table->block + in_offset;
213
0
    }
214
215
    /* add the object to the base block and adjust offset */
216
0
    table->elements[idx] = FT_OFFSET( table->block, table->cursor );
217
0
    table->lengths [idx] = length;
218
0
    FT_MEM_COPY( table->block + table->cursor, object, length );
219
220
0
    table->cursor += length;
221
0
    return FT_Err_Ok;
222
0
  }
223
224
225
  /**************************************************************************
226
   *
227
   * @Function:
228
   *   ps_table_done
229
   *
230
   * @Description:
231
   *   Finalizes a PS_TableRec (i.e., reallocate it to its current
232
   *   cursor).
233
   *
234
   * @InOut:
235
   *   table ::
236
   *     The target table.
237
   *
238
   * @Note:
239
   *   This function does NOT release the heap's memory block.  It is up
240
   *   to the caller to clean it, or reference it in its own structures.
241
   */
242
  FT_LOCAL_DEF( void )
243
  ps_table_done( PS_Table  table )
244
0
  {
245
0
    FT_Memory  memory = table->memory;
246
0
    FT_Error   error;
247
0
    FT_Byte*   old_base = table->block;
248
249
250
    /* should never fail, because rec.cursor <= rec.size */
251
0
    if ( !old_base )
252
0
      return;
253
254
0
    if ( FT_QALLOC( table->block, table->cursor ) )
255
0
      return;
256
0
    FT_MEM_COPY( table->block, old_base, table->cursor );
257
0
    shift_elements( table, old_base );
258
259
0
    table->capacity = table->cursor;
260
0
    FT_FREE( old_base );
261
262
0
    FT_UNUSED( error );
263
0
  }
264
265
266
  FT_LOCAL_DEF( void )
267
  ps_table_release( PS_Table  table )
268
0
  {
269
0
    FT_Memory  memory = table->memory;
270
271
272
0
    if ( (FT_ULong)table->init == 0xDEADBEEFUL )
273
0
    {
274
0
      FT_FREE( table->block );
275
0
      FT_FREE( table->elements );
276
0
      FT_FREE( table->lengths );
277
0
      table->init = 0;
278
0
    }
279
0
  }
280
281
282
  /*************************************************************************/
283
  /*************************************************************************/
284
  /*****                                                               *****/
285
  /*****                            T1 PARSER                          *****/
286
  /*****                                                               *****/
287
  /*************************************************************************/
288
  /*************************************************************************/
289
290
291
  /* first character must be already part of the comment */
292
293
  static void
294
  skip_comment( FT_Byte*  *acur,
295
                FT_Byte*   limit )
296
883
  {
297
883
    FT_Byte*  cur = *acur;
298
299
300
1.66M
    while ( cur < limit )
301
1.66M
    {
302
1.66M
      if ( IS_PS_NEWLINE( *cur ) )
303
868
        break;
304
1.66M
      cur++;
305
1.66M
    }
306
307
883
    *acur = cur;
308
883
  }
309
310
311
  static void
312
  skip_spaces( FT_Byte*  *acur,
313
               FT_Byte*   limit )
314
30.6k
  {
315
30.6k
    FT_Byte*  cur = *acur;
316
317
318
61.0k
    while ( cur < limit )
319
61.0k
    {
320
61.0k
      if ( !IS_PS_SPACE( *cur ) )
321
31.4k
      {
322
31.4k
        if ( *cur == '%' )
323
          /* According to the PLRM, a comment is equal to a space. */
324
837
          skip_comment( &cur, limit );
325
30.5k
        else
326
30.5k
          break;
327
30.4k
      }
328
30.4k
      cur++;
329
30.4k
    }
330
331
30.6k
    *acur = cur;
332
30.6k
  }
333
334
335
10.6k
#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
336
337
338
  /* first character must be `(';                               */
339
  /* *acur is positioned at the character after the closing `)' */
340
341
  static FT_Error
342
  skip_literal_string( FT_Byte*  *acur,
343
                       FT_Byte*   limit )
344
374
  {
345
374
    FT_Byte*      cur   = *acur;
346
374
    FT_Int        embed = 0;
347
374
    FT_Error      error = FT_ERR( Invalid_File_Format );
348
374
    unsigned int  i;
349
350
351
5.44M
    while ( cur < limit )
352
5.44M
    {
353
5.44M
      FT_Byte  c = *cur;
354
355
356
5.44M
      cur++;
357
358
5.44M
      if ( c == '\\' )
359
59.7k
      {
360
        /* Red Book 3rd ed., section `Literal Text Strings', p. 29:     */
361
        /* A backslash can introduce three different types              */
362
        /* of escape sequences:                                         */
363
        /*   - a special escaped char like \r, \n, etc.                 */
364
        /*   - a one-, two-, or three-digit octal number                */
365
        /*   - none of the above in which case the backslash is ignored */
366
367
59.7k
        if ( cur == limit )
368
          /* error (or to be ignored?) */
369
4
          break;
370
371
59.7k
        switch ( *cur )
372
59.7k
        {
373
          /* skip `special' escape */
374
115
        case 'n':
375
142
        case 'r':
376
191
        case 't':
377
221
        case 'b':
378
282
        case 'f':
379
49.1k
        case '\\':
380
49.1k
        case '(':
381
49.2k
        case ')':
382
49.2k
          cur++;
383
49.2k
          break;
384
385
10.5k
        default:
386
          /* skip octal escape or ignore backslash */
387
10.6k
          for ( i = 0; i < 3 && cur < limit; i++ )
388
10.6k
          {
389
10.6k
            if ( !IS_OCTAL_DIGIT( *cur ) )
390
10.5k
              break;
391
392
122
            cur++;
393
122
          }
394
59.7k
        }
395
59.7k
      }
396
5.38M
      else if ( c == '(' )
397
11.7k
        embed++;
398
5.37M
      else if ( c == ')' )
399
9.23k
      {
400
9.23k
        embed--;
401
9.23k
        if ( embed == 0 )
402
258
        {
403
258
          error = FT_Err_Ok;
404
258
          break;
405
258
        }
406
9.23k
      }
407
5.44M
    }
408
409
374
    *acur = cur;
410
411
374
    return error;
412
374
  }
413
414
415
  /* first character must be `<' */
416
417
  static FT_Error
418
  skip_string( FT_Byte*  *acur,
419
               FT_Byte*   limit )
420
193
  {
421
193
    FT_Byte*  cur = *acur;
422
193
    FT_Error  err =  FT_Err_Ok;
423
424
425
245
    while ( ++cur < limit )
426
245
    {
427
      /* All whitespace characters are ignored. */
428
245
      skip_spaces( &cur, limit );
429
245
      if ( cur >= limit )
430
0
        break;
431
432
245
      if ( !IS_PS_XDIGIT( *cur ) )
433
193
        break;
434
245
    }
435
436
193
    if ( cur < limit && *cur != '>' )
437
192
    {
438
192
      FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
439
192
      err = FT_THROW( Invalid_File_Format );
440
192
    }
441
1
    else
442
1
      cur++;
443
444
193
    *acur = cur;
445
193
    return err;
446
193
  }
447
448
449
  /* first character must be the opening brace that */
450
  /* starts the procedure                           */
451
452
  /* NB: [ and ] need not match:                    */
453
  /* `/foo {[} def' is a valid PostScript fragment, */
454
  /* even within a Type1 font                       */
455
456
  static FT_Error
457
  skip_procedure( FT_Byte*  *acur,
458
                  FT_Byte*   limit )
459
136
  {
460
136
    FT_Byte*  cur;
461
136
    FT_Int    embed = 0;
462
136
    FT_Error  error = FT_Err_Ok;
463
464
465
136
    FT_ASSERT( **acur == '{' );
466
467
29.1k
    for ( cur = *acur; cur < limit && error == FT_Err_Ok; cur++ )
468
29.0k
    {
469
29.0k
      switch ( *cur )
470
29.0k
      {
471
306
      case '{':
472
306
        embed++;
473
306
        break;
474
475
168
      case '}':
476
168
        embed--;
477
168
        if ( embed == 0 )
478
80
        {
479
80
          cur++;
480
80
          goto end;
481
80
        }
482
88
        break;
483
484
81
      case '(':
485
81
        error = skip_literal_string( &cur, limit );
486
81
        break;
487
488
42
      case '<':
489
42
        error = skip_string( &cur, limit );
490
42
        break;
491
492
46
      case '%':
493
46
        skip_comment( &cur, limit );
494
46
        break;
495
29.0k
      }
496
29.0k
    }
497
498
136
  end:
499
136
    if ( embed != 0 )
500
56
      error = FT_THROW( Invalid_File_Format );
501
502
136
    *acur = cur;
503
504
136
    return error;
505
136
  }
506
507
508
  /************************************************************************
509
   *
510
   * All exported parsing routines handle leading whitespace and stop at
511
   * the first character which isn't part of the just handled token.
512
   *
513
   */
514
515
516
  FT_LOCAL_DEF( void )
517
  ps_parser_skip_PS_token( PS_Parser  parser )
518
15.1k
  {
519
    /* Note: PostScript allows any non-delimiting, non-whitespace        */
520
    /*       character in a name (PS Ref Manual, 3rd ed, p31).           */
521
    /*       PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
522
523
15.1k
    FT_Byte*  cur   = parser->cursor;
524
15.1k
    FT_Byte*  limit = parser->limit;
525
15.1k
    FT_Error  error = FT_Err_Ok;
526
527
528
15.1k
    skip_spaces( &cur, limit );             /* this also skips comments */
529
15.1k
    if ( cur >= limit )
530
0
      goto Exit;
531
532
    /* self-delimiting, single-character tokens */
533
15.1k
    if ( *cur == '[' || *cur == ']' )
534
309
    {
535
309
      cur++;
536
309
      goto Exit;
537
309
    }
538
539
    /* skip balanced expressions (procedures and strings) */
540
541
14.8k
    if ( *cur == '{' )                              /* {...} */
542
136
    {
543
136
      error = skip_procedure( &cur, limit );
544
136
      goto Exit;
545
136
    }
546
547
14.7k
    if ( *cur == '(' )                              /* (...) */
548
293
    {
549
293
      error = skip_literal_string( &cur, limit );
550
293
      goto Exit;
551
293
    }
552
553
14.4k
    if ( *cur == '<' )                              /* <...> */
554
195
    {
555
195
      if ( cur + 1 < limit && *(cur + 1) == '<' )   /* << */
556
44
      {
557
44
        cur++;
558
44
        cur++;
559
44
      }
560
151
      else
561
151
        error = skip_string( &cur, limit );
562
563
195
      goto Exit;
564
195
    }
565
566
14.2k
    if ( *cur == '>' )
567
28
    {
568
28
      cur++;
569
28
      if ( cur >= limit || *cur != '>' )             /* >> */
570
27
      {
571
27
        FT_ERROR(( "ps_parser_skip_PS_token:"
572
27
                   " unexpected closing delimiter `>'\n" ));
573
27
        error = FT_THROW( Invalid_File_Format );
574
27
        goto Exit;
575
27
      }
576
1
      cur++;
577
1
      goto Exit;
578
1
    }
579
580
14.2k
    if ( *cur == '/' )
581
0
      cur++;
582
583
    /* anything else */
584
116k
    while ( cur < limit )
585
116k
    {
586
      /* *cur might be invalid (e.g., ')' or '}'), but this   */
587
      /* is handled by the test `cur == parser->cursor' below */
588
116k
      if ( IS_PS_DELIM( *cur ) )
589
14.2k
        break;
590
591
102k
      cur++;
592
102k
    }
593
594
15.1k
  Exit:
595
15.1k
    if ( cur < limit && cur == parser->cursor )
596
79
    {
597
79
      FT_ERROR(( "ps_parser_skip_PS_token:"
598
79
                 " current token is `%c' which is self-delimiting\n",
599
79
                 *cur ));
600
79
      FT_ERROR(( "                        "
601
79
                 " but invalid at this point\n" ));
602
603
79
      error = FT_THROW( Invalid_File_Format );
604
79
    }
605
606
15.1k
    if ( cur > limit )
607
14
      cur = limit;
608
609
15.1k
    parser->error  = error;
610
15.1k
    parser->cursor = cur;
611
15.1k
  }
612
613
614
  FT_LOCAL_DEF( void )
615
  ps_parser_skip_spaces( PS_Parser  parser )
616
15.1k
  {
617
15.1k
    skip_spaces( &parser->cursor, parser->limit );
618
15.1k
  }
619
620
621
  /* `token' here means either something between balanced delimiters */
622
  /* or the next token; the delimiters are not removed.              */
623
624
  FT_LOCAL_DEF( void )
625
  ps_parser_to_token( PS_Parser  parser,
626
                      T1_Token   token )
627
0
  {
628
0
    FT_Byte*  cur;
629
0
    FT_Byte*  limit;
630
0
    FT_Int    embed;
631
632
633
0
    token->type  = T1_TOKEN_TYPE_NONE;
634
0
    token->start = NULL;
635
0
    token->limit = NULL;
636
637
    /* first of all, skip leading whitespace */
638
0
    ps_parser_skip_spaces( parser );
639
640
0
    cur   = parser->cursor;
641
0
    limit = parser->limit;
642
643
0
    if ( cur >= limit )
644
0
      return;
645
646
0
    switch ( *cur )
647
0
    {
648
      /************* check for literal string *****************/
649
0
    case '(':
650
0
      token->type  = T1_TOKEN_TYPE_STRING;
651
0
      token->start = cur;
652
653
0
      if ( skip_literal_string( &cur, limit ) == FT_Err_Ok )
654
0
        token->limit = cur;
655
0
      break;
656
657
      /************* check for programs/array *****************/
658
0
    case '{':
659
0
      token->type  = T1_TOKEN_TYPE_ARRAY;
660
0
      token->start = cur;
661
662
0
      if ( skip_procedure( &cur, limit ) == FT_Err_Ok )
663
0
        token->limit = cur;
664
0
      break;
665
666
      /************* check for table/array ********************/
667
      /* XXX: in theory we should also look for "<<"          */
668
      /*      since this is semantically equivalent to "[";   */
669
      /*      in practice it doesn't matter (?)               */
670
0
    case '[':
671
0
      token->type  = T1_TOKEN_TYPE_ARRAY;
672
0
      embed        = 1;
673
0
      token->start = cur++;
674
675
      /* we need this to catch `[ ]' */
676
0
      parser->cursor = cur;
677
0
      ps_parser_skip_spaces( parser );
678
0
      cur = parser->cursor;
679
680
0
      while ( cur < limit && !parser->error )
681
0
      {
682
        /* XXX: this is wrong because it does not      */
683
        /*      skip comments, procedures, and strings */
684
0
        if ( *cur == '[' )
685
0
          embed++;
686
0
        else if ( *cur == ']' )
687
0
        {
688
0
          embed--;
689
0
          if ( embed <= 0 )
690
0
          {
691
0
            token->limit = ++cur;
692
0
            break;
693
0
          }
694
0
        }
695
696
0
        parser->cursor = cur;
697
0
        ps_parser_skip_PS_token( parser );
698
        /* we need this to catch `[XXX ]' */
699
0
        ps_parser_skip_spaces  ( parser );
700
0
        cur = parser->cursor;
701
0
      }
702
0
      break;
703
704
      /* ************ otherwise, it is any token **************/
705
0
    default:
706
0
      token->start = cur;
707
0
      token->type  = ( *cur == '/' ) ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY;
708
0
      ps_parser_skip_PS_token( parser );
709
0
      cur = parser->cursor;
710
0
      if ( !parser->error )
711
0
        token->limit = cur;
712
0
    }
713
714
0
    if ( !token->limit )
715
0
    {
716
0
      token->start = NULL;
717
0
      token->type  = T1_TOKEN_TYPE_NONE;
718
0
    }
719
720
0
    parser->cursor = cur;
721
0
  }
722
723
724
  /* NB: `tokens' can be NULL if we only want to count */
725
  /* the number of array elements                      */
726
727
  FT_LOCAL_DEF( void )
728
  ps_parser_to_token_array( PS_Parser  parser,
729
                            T1_Token   tokens,
730
                            FT_UInt    max_tokens,
731
                            FT_Int*    pnum_tokens )
732
0
  {
733
0
    T1_TokenRec  master;
734
735
736
0
    *pnum_tokens = -1;
737
738
    /* this also handles leading whitespace */
739
0
    ps_parser_to_token( parser, &master );
740
741
0
    if ( master.type == T1_TOKEN_TYPE_ARRAY )
742
0
    {
743
0
      FT_Byte*  old_cursor = parser->cursor;
744
0
      FT_Byte*  old_limit  = parser->limit;
745
0
      T1_Token  cur        = tokens;
746
0
      T1_Token  limit      = cur + max_tokens;
747
748
749
      /* don't include outermost delimiters */
750
0
      parser->cursor = master.start + 1;
751
0
      parser->limit  = master.limit - 1;
752
753
0
      while ( parser->cursor < parser->limit )
754
0
      {
755
0
        T1_TokenRec  token;
756
757
758
0
        ps_parser_to_token( parser, &token );
759
0
        if ( !token.type )
760
0
          break;
761
762
0
        if ( tokens && cur < limit )
763
0
          *cur = token;
764
765
0
        cur++;
766
0
      }
767
768
0
      *pnum_tokens = (FT_Int)( cur - tokens );
769
770
0
      parser->cursor = old_cursor;
771
0
      parser->limit  = old_limit;
772
0
    }
773
0
  }
774
775
776
  /* first character must be a delimiter or a part of a number */
777
  /* NB: `coords' can be NULL if we just want to skip the      */
778
  /*     array; in this case we ignore `max_coords'            */
779
780
  static FT_Int
781
  ps_tocoordarray( FT_Byte*  *acur,
782
                   FT_Byte*   limit,
783
                   FT_Int     max_coords,
784
                   FT_Short*  coords )
785
0
  {
786
0
    FT_Byte*  cur   = *acur;
787
0
    FT_Int    count = 0;
788
0
    FT_Byte   c, ender;
789
790
791
0
    if ( cur >= limit )
792
0
      goto Exit;
793
794
    /* check for the beginning of an array; otherwise, only one number */
795
    /* will be read                                                    */
796
0
    c     = *cur;
797
0
    ender = 0;
798
799
0
    if ( c == '[' )
800
0
      ender = ']';
801
0
    else if ( c == '{' )
802
0
      ender = '}';
803
804
0
    if ( ender )
805
0
      cur++;
806
807
    /* now, read the coordinates */
808
0
    while ( cur < limit )
809
0
    {
810
0
      FT_Short  dummy;
811
0
      FT_Byte*  old_cur;
812
813
814
      /* skip whitespace in front of data */
815
0
      skip_spaces( &cur, limit );
816
0
      if ( cur >= limit )
817
0
        goto Exit;
818
819
0
      if ( *cur == ender )
820
0
      {
821
0
        cur++;
822
0
        break;
823
0
      }
824
825
0
      old_cur = cur;
826
827
0
      if ( coords && count >= max_coords )
828
0
        break;
829
830
      /* call PS_Conv_ToFixed() even if coords == NULL */
831
      /* to properly parse number at `cur'             */
832
0
      *( coords ? &coords[count] : &dummy ) =
833
0
        (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
834
835
0
      if ( old_cur == cur )
836
0
      {
837
0
        count = -1;
838
0
        goto Exit;
839
0
      }
840
0
      else
841
0
        count++;
842
843
0
      if ( !ender )
844
0
        break;
845
0
    }
846
847
0
  Exit:
848
0
    *acur = cur;
849
0
    return count;
850
0
  }
851
852
853
  /* first character must be a delimiter or a part of a number */
854
  /* NB: `values' can be NULL if we just want to skip the      */
855
  /*     array; in this case we ignore `max_values'            */
856
  /*                                                           */
857
  /* return number of successfully parsed values               */
858
859
  static FT_Int
860
  ps_tofixedarray( FT_Byte*  *acur,
861
                   FT_Byte*   limit,
862
                   FT_Int     max_values,
863
                   FT_Fixed*  values,
864
                   FT_Int     power_ten )
865
0
  {
866
0
    FT_Byte*  cur   = *acur;
867
0
    FT_Int    count = 0;
868
0
    FT_Byte   c, ender;
869
870
871
0
    if ( cur >= limit )
872
0
      goto Exit;
873
874
    /* Check for the beginning of an array.  Otherwise, only one number */
875
    /* will be read.                                                    */
876
0
    c     = *cur;
877
0
    ender = 0;
878
879
0
    if ( c == '[' )
880
0
      ender = ']';
881
0
    else if ( c == '{' )
882
0
      ender = '}';
883
884
0
    if ( ender )
885
0
      cur++;
886
887
    /* now, read the values */
888
0
    while ( cur < limit )
889
0
    {
890
0
      FT_Fixed  dummy;
891
0
      FT_Byte*  old_cur;
892
893
894
      /* skip whitespace in front of data */
895
0
      skip_spaces( &cur, limit );
896
0
      if ( cur >= limit )
897
0
        goto Exit;
898
899
0
      if ( *cur == ender )
900
0
      {
901
0
        cur++;
902
0
        break;
903
0
      }
904
905
0
      old_cur = cur;
906
907
0
      if ( values && count >= max_values )
908
0
        break;
909
910
      /* call PS_Conv_ToFixed() even if coords == NULL */
911
      /* to properly parse number at `cur'             */
912
0
      *( values ? &values[count] : &dummy ) =
913
0
        PS_Conv_ToFixed( &cur, limit, power_ten );
914
915
0
      if ( old_cur == cur )
916
0
      {
917
0
        count = -1;
918
0
        goto Exit;
919
0
      }
920
0
      else
921
0
        count++;
922
923
0
      if ( !ender )
924
0
        break;
925
0
    }
926
927
0
  Exit:
928
0
    *acur = cur;
929
0
    return count;
930
0
  }
931
932
933
#if 0
934
935
  static FT_String*
936
  ps_tostring( FT_Byte**  cursor,
937
               FT_Byte*   limit,
938
               FT_Memory  memory )
939
  {
940
    FT_Byte*    cur = *cursor;
941
    FT_UInt     len = 0;
942
    FT_Int      count;
943
    FT_String*  result;
944
    FT_Error    error;
945
946
947
    /* XXX: some stupid fonts have a `Notice' or `Copyright' string     */
948
    /*      that simply doesn't begin with an opening parenthesis, even */
949
    /*      though they have a closing one!  E.g. "amuncial.pfb"        */
950
    /*                                                                  */
951
    /*      We must deal with these ill-fated cases there.  Note that   */
952
    /*      these fonts didn't work with the old Type 1 driver as the   */
953
    /*      notice/copyright was not recognized as a valid string token */
954
    /*      and made the old token parser commit errors.                */
955
956
    while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
957
      cur++;
958
    if ( cur + 1 >= limit )
959
      return 0;
960
961
    if ( *cur == '(' )
962
      cur++;  /* skip the opening parenthesis, if there is one */
963
964
    *cursor = cur;
965
    count   = 0;
966
967
    /* then, count its length */
968
    for ( ; cur < limit; cur++ )
969
    {
970
      if ( *cur == '(' )
971
        count++;
972
973
      else if ( *cur == ')' )
974
      {
975
        count--;
976
        if ( count < 0 )
977
          break;
978
      }
979
    }
980
981
    len = (FT_UInt)( cur - *cursor );
982
    if ( cur >= limit || FT_QALLOC( result, len + 1 ) )
983
      return 0;
984
985
    /* now copy the string */
986
    FT_MEM_COPY( result, *cursor, len );
987
    result[len] = '\0';
988
    *cursor = cur;
989
    return result;
990
  }
991
992
#endif /* 0 */
993
994
995
  static int
996
  ps_tobool( FT_Byte*  *acur,
997
             FT_Byte*   limit )
998
0
  {
999
0
    FT_Byte*  cur    = *acur;
1000
0
    FT_Bool   result = 0;
1001
1002
1003
    /* return 1 if we find `true', 0 otherwise */
1004
0
    if ( cur + 3 < limit &&
1005
0
         cur[0] == 't'   &&
1006
0
         cur[1] == 'r'   &&
1007
0
         cur[2] == 'u'   &&
1008
0
         cur[3] == 'e'   )
1009
0
    {
1010
0
      result = 1;
1011
0
      cur   += 5;
1012
0
    }
1013
0
    else if ( cur + 4 < limit &&
1014
0
              cur[0] == 'f'   &&
1015
0
              cur[1] == 'a'   &&
1016
0
              cur[2] == 'l'   &&
1017
0
              cur[3] == 's'   &&
1018
0
              cur[4] == 'e'   )
1019
0
    {
1020
0
      result = 0;
1021
0
      cur   += 6;
1022
0
    }
1023
1024
0
    *acur = cur;
1025
0
    return result;
1026
0
  }
1027
1028
1029
  /* load a simple field (i.e. non-table) into the current list of objects */
1030
1031
  FT_LOCAL_DEF( FT_Error )
1032
  ps_parser_load_field( PS_Parser       parser,
1033
                        const T1_Field  field,
1034
                        void**          objects,
1035
                        FT_UInt         max_objects,
1036
                        FT_ULong*       pflags )
1037
0
  {
1038
0
    T1_TokenRec   token;
1039
0
    FT_Byte*      cur;
1040
0
    FT_Byte*      limit;
1041
0
    FT_UInt       count;
1042
0
    FT_UInt       idx;
1043
0
    FT_Error      error;
1044
0
    T1_FieldType  type;
1045
1046
1047
    /* this also skips leading whitespace */
1048
0
    ps_parser_to_token( parser, &token );
1049
0
    if ( !token.type )
1050
0
      goto Fail;
1051
1052
0
    count = 1;
1053
0
    idx   = 0;
1054
0
    cur   = token.start;
1055
0
    limit = token.limit;
1056
1057
0
    type = field->type;
1058
1059
    /* we must detect arrays in /FontBBox */
1060
0
    if ( type == T1_FIELD_TYPE_BBOX )
1061
0
    {
1062
0
      T1_TokenRec  token2;
1063
0
      FT_Byte*     old_cur   = parser->cursor;
1064
0
      FT_Byte*     old_limit = parser->limit;
1065
1066
1067
      /* don't include delimiters */
1068
0
      parser->cursor = token.start + 1;
1069
0
      parser->limit  = token.limit - 1;
1070
1071
0
      ps_parser_to_token( parser, &token2 );
1072
0
      parser->cursor = old_cur;
1073
0
      parser->limit  = old_limit;
1074
1075
0
      if ( token2.type == T1_TOKEN_TYPE_ARRAY )
1076
0
      {
1077
0
        type = T1_FIELD_TYPE_MM_BBOX;
1078
0
        goto FieldArray;
1079
0
      }
1080
0
    }
1081
0
    else if ( token.type == T1_TOKEN_TYPE_ARRAY )
1082
0
    {
1083
0
      count = max_objects;
1084
1085
0
    FieldArray:
1086
      /* if this is an array and we have no blend, an error occurs */
1087
0
      if ( max_objects == 0 )
1088
0
        goto Fail;
1089
1090
0
      idx = 1;
1091
1092
      /* don't include delimiters */
1093
0
      cur++;
1094
0
      limit--;
1095
0
    }
1096
1097
0
    for ( ; count > 0; count--, idx++ )
1098
0
    {
1099
0
      FT_Byte*    q      = (FT_Byte*)objects[idx] + field->offset;
1100
0
      FT_Long     val;
1101
0
      FT_String*  string = NULL;
1102
1103
1104
0
      skip_spaces( &cur, limit );
1105
1106
0
      switch ( type )
1107
0
      {
1108
0
      case T1_FIELD_TYPE_BOOL:
1109
0
        val = ps_tobool( &cur, limit );
1110
0
        FT_TRACE4(( " %s", val ? "true" : "false" ));
1111
0
        goto Store_Integer;
1112
1113
0
      case T1_FIELD_TYPE_FIXED:
1114
0
        val = PS_Conv_ToFixed( &cur, limit, 0 );
1115
0
        FT_TRACE4(( " %f", (double)val / 65536 ));
1116
0
        goto Store_Integer;
1117
1118
0
      case T1_FIELD_TYPE_FIXED_1000:
1119
0
        val = PS_Conv_ToFixed( &cur, limit, 3 );
1120
0
        FT_TRACE4(( " %f", (double)val / 65536 / 1000 ));
1121
0
        goto Store_Integer;
1122
1123
0
      case T1_FIELD_TYPE_INTEGER:
1124
0
        val = PS_Conv_ToInt( &cur, limit );
1125
0
        FT_TRACE4(( " %ld", val ));
1126
        /* fall through */
1127
1128
0
      Store_Integer:
1129
0
        switch ( field->size )
1130
0
        {
1131
0
        case (8 / FT_CHAR_BIT):
1132
0
          *(FT_Byte*)q = (FT_Byte)val;
1133
0
          break;
1134
1135
0
        case (16 / FT_CHAR_BIT):
1136
0
          *(FT_UShort*)q = (FT_UShort)val;
1137
0
          break;
1138
1139
0
        case (32 / FT_CHAR_BIT):
1140
0
          *(FT_UInt32*)q = (FT_UInt32)val;
1141
0
          break;
1142
1143
0
        default:                /* for 64-bit systems */
1144
0
          *(FT_Long*)q = val;
1145
0
        }
1146
0
        break;
1147
1148
0
      case T1_FIELD_TYPE_STRING:
1149
0
      case T1_FIELD_TYPE_KEY:
1150
0
        {
1151
0
          FT_Memory  memory = parser->memory;
1152
0
          FT_UInt    len    = (FT_UInt)( limit - cur );
1153
1154
1155
0
          if ( cur >= limit )
1156
0
            break;
1157
1158
          /* we allow both a string or a name   */
1159
          /* for cases like /FontName (foo) def */
1160
0
          if ( token.type == T1_TOKEN_TYPE_KEY )
1161
0
          {
1162
            /* don't include leading `/' */
1163
0
            len--;
1164
0
            cur++;
1165
0
          }
1166
0
          else if ( token.type == T1_TOKEN_TYPE_STRING )
1167
0
          {
1168
            /* don't include delimiting parentheses    */
1169
            /* XXX we don't handle <<...>> here        */
1170
            /* XXX should we convert octal escapes?    */
1171
            /*     if so, what encoding should we use? */
1172
0
            cur++;
1173
0
            len -= 2;
1174
0
          }
1175
0
          else
1176
0
          {
1177
0
            FT_ERROR(( "ps_parser_load_field:"
1178
0
                       " expected a name or string\n" ));
1179
0
            FT_ERROR(( "                     "
1180
0
                       " but found token of type %d instead\n",
1181
0
                       token.type ));
1182
0
            error = FT_THROW( Invalid_File_Format );
1183
0
            goto Exit;
1184
0
          }
1185
1186
          /* for this to work (FT_String**)q must have been */
1187
          /* initialized to NULL                            */
1188
0
          if ( *(FT_String**)q )
1189
0
          {
1190
0
            FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1191
0
                        field->ident ));
1192
0
            FT_FREE( *(FT_String**)q );
1193
0
            *(FT_String**)q = NULL;
1194
0
          }
1195
1196
0
          if ( FT_QALLOC( string, len + 1 ) )
1197
0
            goto Exit;
1198
1199
0
          FT_MEM_COPY( string, cur, len );
1200
0
          string[len] = 0;
1201
1202
#ifdef FT_DEBUG_LEVEL_TRACE
1203
          if ( token.type == T1_TOKEN_TYPE_STRING )
1204
            FT_TRACE4(( " (%s)", string ));
1205
          else
1206
            FT_TRACE4(( " /%s", string ));
1207
#endif
1208
1209
0
          *(FT_String**)q = string;
1210
0
        }
1211
0
        break;
1212
1213
0
      case T1_FIELD_TYPE_BBOX:
1214
0
        {
1215
0
          FT_Fixed  temp[4];
1216
0
          FT_BBox*  bbox = (FT_BBox*)q;
1217
0
          FT_Int    result;
1218
1219
1220
0
          result = ps_tofixedarray( &cur, limit, 4, temp, 0 );
1221
1222
0
          if ( result < 4 )
1223
0
          {
1224
0
            FT_ERROR(( "ps_parser_load_field:"
1225
0
                       " expected four integers in bounding box\n" ));
1226
0
            error = FT_THROW( Invalid_File_Format );
1227
0
            goto Exit;
1228
0
          }
1229
1230
0
          bbox->xMin = FT_RoundFix( temp[0] );
1231
0
          bbox->yMin = FT_RoundFix( temp[1] );
1232
0
          bbox->xMax = FT_RoundFix( temp[2] );
1233
0
          bbox->yMax = FT_RoundFix( temp[3] );
1234
1235
0
          FT_TRACE4(( " [%ld %ld %ld %ld]",
1236
0
                      bbox->xMin / 65536,
1237
0
                      bbox->yMin / 65536,
1238
0
                      bbox->xMax / 65536,
1239
0
                      bbox->yMax / 65536 ));
1240
0
        }
1241
0
        break;
1242
1243
0
      case T1_FIELD_TYPE_MM_BBOX:
1244
0
        {
1245
0
          FT_Memory  memory = parser->memory;
1246
0
          FT_Fixed*  temp   = NULL;
1247
0
          FT_Int     result;
1248
0
          FT_UInt    i;
1249
1250
1251
0
          if ( FT_QNEW_ARRAY( temp, max_objects * 4 ) )
1252
0
            goto Exit;
1253
1254
0
          for ( i = 0; i < 4; i++ )
1255
0
          {
1256
0
            result = ps_tofixedarray( &cur, limit, (FT_Int)max_objects,
1257
0
                                      temp + i * max_objects, 0 );
1258
0
            if ( result < 0 || (FT_UInt)result < max_objects )
1259
0
            {
1260
0
              FT_ERROR(( "ps_parser_load_field:"
1261
0
                         " expected %d integer%s in the %s subarray\n",
1262
0
                         max_objects, max_objects > 1 ? "s" : "",
1263
0
                         i == 0 ? "first"
1264
0
                                : ( i == 1 ? "second"
1265
0
                                           : ( i == 2 ? "third"
1266
0
                                                      : "fourth" ) ) ));
1267
0
              FT_ERROR(( "                     "
1268
0
                         " of /FontBBox in the /Blend dictionary\n" ));
1269
0
              error = FT_THROW( Invalid_File_Format );
1270
1271
0
              FT_FREE( temp );
1272
0
              goto Exit;
1273
0
            }
1274
1275
0
            skip_spaces( &cur, limit );
1276
0
          }
1277
1278
0
          FT_TRACE4(( " [" ));
1279
0
          for ( i = 0; i < max_objects; i++ )
1280
0
          {
1281
0
            FT_BBox*  bbox = (FT_BBox*)objects[i];
1282
1283
1284
0
            bbox->xMin = FT_RoundFix( temp[i                  ] );
1285
0
            bbox->yMin = FT_RoundFix( temp[i +     max_objects] );
1286
0
            bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] );
1287
0
            bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] );
1288
1289
0
            FT_TRACE4(( " [%ld %ld %ld %ld]",
1290
0
                        bbox->xMin / 65536,
1291
0
                        bbox->yMin / 65536,
1292
0
                        bbox->xMax / 65536,
1293
0
                        bbox->yMax / 65536 ));
1294
0
          }
1295
0
          FT_TRACE4(( "]" ));
1296
1297
0
          FT_FREE( temp );
1298
0
        }
1299
0
        break;
1300
1301
0
      default:
1302
        /* an error occurred */
1303
0
        goto Fail;
1304
0
      }
1305
0
    }
1306
1307
#if 0  /* obsolete -- keep for reference */
1308
    if ( pflags )
1309
      *pflags |= 1L << field->flag_bit;
1310
#else
1311
0
    FT_UNUSED( pflags );
1312
0
#endif
1313
1314
0
    error = FT_Err_Ok;
1315
1316
0
  Exit:
1317
0
    return error;
1318
1319
0
  Fail:
1320
0
    error = FT_THROW( Invalid_File_Format );
1321
0
    goto Exit;
1322
0
  }
1323
1324
1325
0
#define T1_MAX_TABLE_ELEMENTS  32
1326
1327
1328
  FT_LOCAL_DEF( FT_Error )
1329
  ps_parser_load_field_table( PS_Parser       parser,
1330
                              const T1_Field  field,
1331
                              void**          objects,
1332
                              FT_UInt         max_objects,
1333
                              FT_ULong*       pflags )
1334
0
  {
1335
0
    T1_TokenRec  elements[T1_MAX_TABLE_ELEMENTS];
1336
0
    T1_Token     token;
1337
0
    FT_Int       num_elements;
1338
0
    FT_Error     error = FT_Err_Ok;
1339
0
    FT_Byte*     old_cursor;
1340
0
    FT_Byte*     old_limit;
1341
0
    T1_FieldRec  fieldrec = *(T1_Field)field;
1342
1343
1344
0
    fieldrec.type = T1_FIELD_TYPE_INTEGER;
1345
0
    if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
1346
0
         field->type == T1_FIELD_TYPE_BBOX        )
1347
0
      fieldrec.type = T1_FIELD_TYPE_FIXED;
1348
1349
0
    ps_parser_to_token_array( parser, elements,
1350
0
                              T1_MAX_TABLE_ELEMENTS, &num_elements );
1351
0
    if ( num_elements < 0 )
1352
0
    {
1353
0
      error = FT_ERR( Ignore );
1354
0
      goto Exit;
1355
0
    }
1356
0
    if ( (FT_UInt)num_elements > field->array_max )
1357
0
      num_elements = (FT_Int)field->array_max;
1358
1359
0
    old_cursor = parser->cursor;
1360
0
    old_limit  = parser->limit;
1361
1362
    /* we store the elements count if necessary;           */
1363
    /* we further assume that `count_offset' can't be zero */
1364
0
    if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 )
1365
0
      *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
1366
0
        (FT_Byte)num_elements;
1367
1368
0
    FT_TRACE4(( " [" ));
1369
1370
    /* we now load each element, adjusting the field.offset on each one */
1371
0
    token = elements;
1372
0
    for ( ; num_elements > 0; num_elements--, token++ )
1373
0
    {
1374
0
      parser->cursor = token->start;
1375
0
      parser->limit  = token->limit;
1376
1377
0
      error = ps_parser_load_field( parser,
1378
0
                                    &fieldrec,
1379
0
                                    objects,
1380
0
                                    max_objects,
1381
0
                                    0 );
1382
0
      if ( error )
1383
0
        break;
1384
1385
0
      fieldrec.offset += fieldrec.size;
1386
0
    }
1387
1388
0
    FT_TRACE4(( "]" ));
1389
1390
#if 0  /* obsolete -- keep for reference */
1391
    if ( pflags )
1392
      *pflags |= 1L << field->flag_bit;
1393
#else
1394
0
    FT_UNUSED( pflags );
1395
0
#endif
1396
1397
0
    parser->cursor = old_cursor;
1398
0
    parser->limit  = old_limit;
1399
1400
0
  Exit:
1401
0
    return error;
1402
0
  }
1403
1404
1405
  FT_LOCAL_DEF( FT_Long )
1406
  ps_parser_to_int( PS_Parser  parser )
1407
0
  {
1408
0
    ps_parser_skip_spaces( parser );
1409
0
    return PS_Conv_ToInt( &parser->cursor, parser->limit );
1410
0
  }
1411
1412
1413
  /* first character must be `<' if `delimiters' is non-zero */
1414
1415
  FT_LOCAL_DEF( FT_Error )
1416
  ps_parser_to_bytes( PS_Parser  parser,
1417
                      FT_Byte*   bytes,
1418
                      FT_Offset  max_bytes,
1419
                      FT_ULong*  pnum_bytes,
1420
                      FT_Bool    delimiters )
1421
0
  {
1422
0
    FT_Error  error = FT_Err_Ok;
1423
0
    FT_Byte*  cur;
1424
1425
1426
0
    ps_parser_skip_spaces( parser );
1427
0
    cur = parser->cursor;
1428
1429
0
    if ( cur >= parser->limit )
1430
0
      goto Exit;
1431
1432
0
    if ( delimiters )
1433
0
    {
1434
0
      if ( *cur != '<' )
1435
0
      {
1436
0
        FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1437
0
        error = FT_THROW( Invalid_File_Format );
1438
0
        goto Exit;
1439
0
      }
1440
1441
0
      cur++;
1442
0
    }
1443
1444
0
    *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
1445
0
                                          parser->limit,
1446
0
                                          bytes,
1447
0
                                          max_bytes );
1448
1449
0
    parser->cursor = cur;
1450
1451
0
    if ( delimiters )
1452
0
    {
1453
0
      if ( cur < parser->limit && *cur != '>' )
1454
0
      {
1455
0
        FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
1456
0
        error = FT_THROW( Invalid_File_Format );
1457
0
        goto Exit;
1458
0
      }
1459
1460
0
      parser->cursor++;
1461
0
    }
1462
1463
0
  Exit:
1464
0
    return error;
1465
0
  }
1466
1467
1468
  FT_LOCAL_DEF( FT_Fixed )
1469
  ps_parser_to_fixed( PS_Parser  parser,
1470
                      FT_Int     power_ten )
1471
0
  {
1472
0
    ps_parser_skip_spaces( parser );
1473
0
    return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
1474
0
  }
1475
1476
1477
  FT_LOCAL_DEF( FT_Int )
1478
  ps_parser_to_coord_array( PS_Parser  parser,
1479
                            FT_Int     max_coords,
1480
                            FT_Short*  coords )
1481
0
  {
1482
0
    ps_parser_skip_spaces( parser );
1483
0
    return ps_tocoordarray( &parser->cursor, parser->limit,
1484
0
                            max_coords, coords );
1485
0
  }
1486
1487
1488
  FT_LOCAL_DEF( FT_Int )
1489
  ps_parser_to_fixed_array( PS_Parser  parser,
1490
                            FT_Int     max_values,
1491
                            FT_Fixed*  values,
1492
                            FT_Int     power_ten )
1493
0
  {
1494
0
    ps_parser_skip_spaces( parser );
1495
0
    return ps_tofixedarray( &parser->cursor, parser->limit,
1496
0
                            max_values, values, power_ten );
1497
0
  }
1498
1499
1500
#if 0
1501
1502
  FT_LOCAL_DEF( FT_String* )
1503
  T1_ToString( PS_Parser  parser )
1504
  {
1505
    return ps_tostring( &parser->cursor, parser->limit, parser->memory );
1506
  }
1507
1508
1509
  FT_LOCAL_DEF( FT_Bool )
1510
  T1_ToBool( PS_Parser  parser )
1511
  {
1512
    return ps_tobool( &parser->cursor, parser->limit );
1513
  }
1514
1515
#endif /* 0 */
1516
1517
1518
  FT_LOCAL_DEF( void )
1519
  ps_parser_init( PS_Parser  parser,
1520
                  FT_Byte*   base,
1521
                  FT_Byte*   limit,
1522
                  FT_Memory  memory )
1523
8.40k
  {
1524
8.40k
    parser->error  = FT_Err_Ok;
1525
8.40k
    parser->base   = base;
1526
8.40k
    parser->limit  = limit;
1527
8.40k
    parser->cursor = base;
1528
8.40k
    parser->memory = memory;
1529
8.40k
    parser->funcs  = ps_parser_funcs;
1530
8.40k
  }
1531
1532
1533
  FT_LOCAL_DEF( void )
1534
  ps_parser_done( PS_Parser  parser )
1535
8.40k
  {
1536
8.40k
    FT_UNUSED( parser );
1537
8.40k
  }
1538
1539
1540
  /*************************************************************************/
1541
  /*************************************************************************/
1542
  /*****                                                               *****/
1543
  /*****                            T1 BUILDER                         *****/
1544
  /*****                                                               *****/
1545
  /*************************************************************************/
1546
  /*************************************************************************/
1547
1548
  /**************************************************************************
1549
   *
1550
   * @Function:
1551
   *   t1_builder_init
1552
   *
1553
   * @Description:
1554
   *   Initializes a given glyph builder.
1555
   *
1556
   * @InOut:
1557
   *   builder ::
1558
   *     A pointer to the glyph builder to initialize.
1559
   *
1560
   * @Input:
1561
   *   face ::
1562
   *     The current face object.
1563
   *
1564
   *   size ::
1565
   *     The current size object.
1566
   *
1567
   *   glyph ::
1568
   *     The current glyph object.
1569
   *
1570
   *   hinting ::
1571
   *     Whether hinting should be applied.
1572
   */
1573
  FT_LOCAL_DEF( void )
1574
  t1_builder_init( T1_Builder    builder,
1575
                   FT_Face       face,
1576
                   FT_Size       size,
1577
                   FT_GlyphSlot  glyph,
1578
                   FT_Bool       hinting )
1579
0
  {
1580
0
    builder->parse_state = T1_Parse_Start;
1581
0
    builder->load_points = 1;
1582
1583
0
    builder->face   = face;
1584
0
    builder->glyph  = glyph;
1585
0
    builder->memory = face->memory;
1586
1587
0
    if ( glyph )
1588
0
    {
1589
0
      FT_GlyphLoader  loader = glyph->internal->loader;
1590
1591
1592
0
      builder->loader  = loader;
1593
0
      builder->base    = &loader->base.outline;
1594
0
      builder->current = &loader->current.outline;
1595
0
      FT_GlyphLoader_Rewind( loader );
1596
1597
0
      builder->hints_globals = size->internal->module_data;
1598
0
      builder->hints_funcs   = NULL;
1599
1600
0
      if ( hinting )
1601
0
        builder->hints_funcs = glyph->internal->glyph_hints;
1602
0
    }
1603
1604
0
    builder->pos_x = 0;
1605
0
    builder->pos_y = 0;
1606
1607
0
    builder->left_bearing.x = 0;
1608
0
    builder->left_bearing.y = 0;
1609
0
    builder->advance.x      = 0;
1610
0
    builder->advance.y      = 0;
1611
1612
0
    builder->funcs = t1_builder_funcs;
1613
0
  }
1614
1615
1616
  /**************************************************************************
1617
   *
1618
   * @Function:
1619
   *   t1_builder_done
1620
   *
1621
   * @Description:
1622
   *   Finalizes a given glyph builder.  Its contents can still be used
1623
   *   after the call, but the function saves important information
1624
   *   within the corresponding glyph slot.
1625
   *
1626
   * @Input:
1627
   *   builder ::
1628
   *     A pointer to the glyph builder to finalize.
1629
   */
1630
  FT_LOCAL_DEF( void )
1631
  t1_builder_done( T1_Builder  builder )
1632
0
  {
1633
0
    FT_GlyphSlot  glyph = builder->glyph;
1634
1635
1636
0
    if ( glyph )
1637
0
      glyph->outline = *builder->base;
1638
0
  }
1639
1640
1641
  /* check that there is enough space for `count' more points */
1642
  FT_LOCAL_DEF( FT_Error )
1643
  t1_builder_check_points( T1_Builder  builder,
1644
                           FT_Int      count )
1645
0
  {
1646
0
    return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1647
0
  }
1648
1649
1650
  /* add a new point, do not check space */
1651
  FT_LOCAL_DEF( void )
1652
  t1_builder_add_point( T1_Builder  builder,
1653
                        FT_Pos      x,
1654
                        FT_Pos      y,
1655
                        FT_Byte     flag )
1656
0
  {
1657
0
    FT_Outline*  outline = builder->current;
1658
1659
1660
0
    if ( builder->load_points )
1661
0
    {
1662
0
      FT_Vector*  point   = outline->points + outline->n_points;
1663
0
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
1664
1665
1666
0
      point->x = FIXED_TO_INT( x );
1667
0
      point->y = FIXED_TO_INT( y );
1668
0
      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1669
0
    }
1670
0
    outline->n_points++;
1671
0
  }
1672
1673
1674
  /* check space for a new on-curve point, then add it */
1675
  FT_LOCAL_DEF( FT_Error )
1676
  t1_builder_add_point1( T1_Builder  builder,
1677
                         FT_Pos      x,
1678
                         FT_Pos      y )
1679
0
  {
1680
0
    FT_Error  error;
1681
1682
1683
0
    error = t1_builder_check_points( builder, 1 );
1684
0
    if ( !error )
1685
0
      t1_builder_add_point( builder, x, y, 1 );
1686
1687
0
    return error;
1688
0
  }
1689
1690
1691
  /* check space for a new contour, then add it */
1692
  FT_LOCAL_DEF( FT_Error )
1693
  t1_builder_add_contour( T1_Builder  builder )
1694
0
  {
1695
0
    FT_Outline*  outline = builder->current;
1696
0
    FT_Error     error;
1697
1698
1699
    /* this might happen in invalid fonts */
1700
0
    if ( !outline )
1701
0
    {
1702
0
      FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" ));
1703
0
      return FT_THROW( Invalid_File_Format );
1704
0
    }
1705
1706
0
    if ( !builder->load_points )
1707
0
    {
1708
0
      outline->n_contours++;
1709
0
      return FT_Err_Ok;
1710
0
    }
1711
1712
0
    error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1713
0
    if ( !error )
1714
0
    {
1715
0
      if ( outline->n_contours > 0 )
1716
0
        outline->contours[outline->n_contours - 1] =
1717
0
          (short)( outline->n_points - 1 );
1718
1719
0
      outline->n_contours++;
1720
0
    }
1721
1722
0
    return error;
1723
0
  }
1724
1725
1726
  /* if a path was begun, add its first on-curve point */
1727
  FT_LOCAL_DEF( FT_Error )
1728
  t1_builder_start_point( T1_Builder  builder,
1729
                          FT_Pos      x,
1730
                          FT_Pos      y )
1731
0
  {
1732
0
    FT_Error  error = FT_ERR( Invalid_File_Format );
1733
1734
1735
    /* test whether we are building a new contour */
1736
1737
0
    if ( builder->parse_state == T1_Parse_Have_Path )
1738
0
      error = FT_Err_Ok;
1739
0
    else
1740
0
    {
1741
0
      builder->parse_state = T1_Parse_Have_Path;
1742
0
      error = t1_builder_add_contour( builder );
1743
0
      if ( !error )
1744
0
        error = t1_builder_add_point1( builder, x, y );
1745
0
    }
1746
1747
0
    return error;
1748
0
  }
1749
1750
1751
  /* close the current contour */
1752
  FT_LOCAL_DEF( void )
1753
  t1_builder_close_contour( T1_Builder  builder )
1754
0
  {
1755
0
    FT_Outline*  outline = builder->current;
1756
0
    FT_Int       first;
1757
1758
1759
0
    if ( !outline )
1760
0
      return;
1761
1762
0
    first = outline->n_contours <= 1
1763
0
            ? 0 : outline->contours[outline->n_contours - 2] + 1;
1764
1765
    /* in malformed fonts it can happen that a contour was started */
1766
    /* but no points were added                                    */
1767
0
    if ( outline->n_contours && first == outline->n_points )
1768
0
    {
1769
0
      outline->n_contours--;
1770
0
      return;
1771
0
    }
1772
1773
    /* We must not include the last point in the path if it */
1774
    /* is located on the first point.                       */
1775
0
    if ( outline->n_points > 1 )
1776
0
    {
1777
0
      FT_Vector*  p1      = outline->points + first;
1778
0
      FT_Vector*  p2      = outline->points + outline->n_points - 1;
1779
0
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
1780
1781
1782
      /* `delete' last point only if it coincides with the first */
1783
      /* point and it is not a control point (which can happen). */
1784
0
      if ( p1->x == p2->x && p1->y == p2->y )
1785
0
        if ( *control == FT_CURVE_TAG_ON )
1786
0
          outline->n_points--;
1787
0
    }
1788
1789
0
    if ( outline->n_contours > 0 )
1790
0
    {
1791
      /* Don't add contours only consisting of one point, i.e.,  */
1792
      /* check whether the first and the last point is the same. */
1793
0
      if ( first == outline->n_points - 1 )
1794
0
      {
1795
0
        outline->n_contours--;
1796
0
        outline->n_points--;
1797
0
      }
1798
0
      else
1799
0
        outline->contours[outline->n_contours - 1] =
1800
0
          (short)( outline->n_points - 1 );
1801
0
    }
1802
0
  }
1803
1804
1805
  /*************************************************************************/
1806
  /*************************************************************************/
1807
  /*****                                                               *****/
1808
  /*****                           CFF BUILDER                         *****/
1809
  /*****                                                               *****/
1810
  /*************************************************************************/
1811
  /*************************************************************************/
1812
1813
1814
  /**************************************************************************
1815
   *
1816
   * @Function:
1817
   *   cff_builder_init
1818
   *
1819
   * @Description:
1820
   *   Initializes a given glyph builder.
1821
   *
1822
   * @InOut:
1823
   *   builder ::
1824
   *     A pointer to the glyph builder to initialize.
1825
   *
1826
   * @Input:
1827
   *   face ::
1828
   *     The current face object.
1829
   *
1830
   *   size ::
1831
   *     The current size object.
1832
   *
1833
   *   glyph ::
1834
   *     The current glyph object.
1835
   *
1836
   *   hinting ::
1837
   *     Whether hinting is active.
1838
   */
1839
  FT_LOCAL_DEF( void )
1840
  cff_builder_init( CFF_Builder*   builder,
1841
                    TT_Face        face,
1842
                    CFF_Size       size,
1843
                    CFF_GlyphSlot  glyph,
1844
                    FT_Bool        hinting )
1845
0
  {
1846
0
    builder->path_begun  = 0;
1847
0
    builder->load_points = 1;
1848
1849
0
    builder->face   = face;
1850
0
    builder->glyph  = glyph;
1851
0
    builder->memory = face->root.memory;
1852
1853
0
    if ( glyph )
1854
0
    {
1855
0
      FT_GlyphLoader  loader = glyph->root.internal->loader;
1856
1857
1858
0
      builder->loader  = loader;
1859
0
      builder->base    = &loader->base.outline;
1860
0
      builder->current = &loader->current.outline;
1861
0
      FT_GlyphLoader_Rewind( loader );
1862
1863
0
      builder->hints_globals = NULL;
1864
0
      builder->hints_funcs   = NULL;
1865
1866
0
      if ( hinting && size )
1867
0
      {
1868
0
        FT_Size       ftsize   = FT_SIZE( size );
1869
0
        CFF_Internal  internal = (CFF_Internal)ftsize->internal->module_data;
1870
1871
0
        if ( internal )
1872
0
        {
1873
0
          builder->hints_globals = (void *)internal->topfont;
1874
0
          builder->hints_funcs   = glyph->root.internal->glyph_hints;
1875
0
        }
1876
0
      }
1877
0
    }
1878
1879
0
    builder->pos_x = 0;
1880
0
    builder->pos_y = 0;
1881
1882
0
    builder->left_bearing.x = 0;
1883
0
    builder->left_bearing.y = 0;
1884
0
    builder->advance.x      = 0;
1885
0
    builder->advance.y      = 0;
1886
1887
0
    builder->funcs = cff_builder_funcs;
1888
0
  }
1889
1890
1891
  /**************************************************************************
1892
   *
1893
   * @Function:
1894
   *   cff_builder_done
1895
   *
1896
   * @Description:
1897
   *   Finalizes a given glyph builder.  Its contents can still be used
1898
   *   after the call, but the function saves important information
1899
   *   within the corresponding glyph slot.
1900
   *
1901
   * @Input:
1902
   *   builder ::
1903
   *     A pointer to the glyph builder to finalize.
1904
   */
1905
  FT_LOCAL_DEF( void )
1906
  cff_builder_done( CFF_Builder*  builder )
1907
0
  {
1908
0
    CFF_GlyphSlot  glyph = builder->glyph;
1909
1910
1911
0
    if ( glyph )
1912
0
      glyph->root.outline = *builder->base;
1913
0
  }
1914
1915
1916
  /* check that there is enough space for `count' more points */
1917
  FT_LOCAL_DEF( FT_Error )
1918
  cff_check_points( CFF_Builder*  builder,
1919
                    FT_Int        count )
1920
0
  {
1921
0
    return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1922
0
  }
1923
1924
1925
  /* add a new point, do not check space */
1926
  FT_LOCAL_DEF( void )
1927
  cff_builder_add_point( CFF_Builder*  builder,
1928
                         FT_Pos        x,
1929
                         FT_Pos        y,
1930
                         FT_Byte       flag )
1931
0
  {
1932
0
    FT_Outline*  outline = builder->current;
1933
1934
1935
0
    if ( builder->load_points )
1936
0
    {
1937
0
      FT_Vector*  point   = outline->points + outline->n_points;
1938
0
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
1939
1940
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
1941
      PS_Driver  driver   = (PS_Driver)FT_FACE_DRIVER( builder->face );
1942
1943
1944
      if ( driver->hinting_engine == FT_HINTING_FREETYPE )
1945
      {
1946
        point->x = x >> 16;
1947
        point->y = y >> 16;
1948
      }
1949
      else
1950
#endif
1951
0
      {
1952
        /* cf2_decoder_parse_charstrings uses 16.16 coordinates */
1953
0
        point->x = x >> 10;
1954
0
        point->y = y >> 10;
1955
0
      }
1956
0
      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1957
0
    }
1958
1959
0
    outline->n_points++;
1960
0
  }
1961
1962
1963
  /* check space for a new on-curve point, then add it */
1964
  FT_LOCAL_DEF( FT_Error )
1965
  cff_builder_add_point1( CFF_Builder*  builder,
1966
                          FT_Pos        x,
1967
                          FT_Pos        y )
1968
0
  {
1969
0
    FT_Error  error;
1970
1971
1972
0
    error = cff_check_points( builder, 1 );
1973
0
    if ( !error )
1974
0
      cff_builder_add_point( builder, x, y, 1 );
1975
1976
0
    return error;
1977
0
  }
1978
1979
1980
  /* check space for a new contour, then add it */
1981
  FT_LOCAL_DEF( FT_Error )
1982
  cff_builder_add_contour( CFF_Builder*  builder )
1983
0
  {
1984
0
    FT_Outline*  outline = builder->current;
1985
0
    FT_Error     error;
1986
1987
1988
0
    if ( !builder->load_points )
1989
0
    {
1990
0
      outline->n_contours++;
1991
0
      return FT_Err_Ok;
1992
0
    }
1993
1994
0
    error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1995
0
    if ( !error )
1996
0
    {
1997
0
      if ( outline->n_contours > 0 )
1998
0
        outline->contours[outline->n_contours - 1] =
1999
0
          (short)( outline->n_points - 1 );
2000
2001
0
      outline->n_contours++;
2002
0
    }
2003
2004
0
    return error;
2005
0
  }
2006
2007
2008
  /* if a path was begun, add its first on-curve point */
2009
  FT_LOCAL_DEF( FT_Error )
2010
  cff_builder_start_point( CFF_Builder*  builder,
2011
                           FT_Pos        x,
2012
                           FT_Pos        y )
2013
0
  {
2014
0
    FT_Error  error = FT_Err_Ok;
2015
2016
2017
    /* test whether we are building a new contour */
2018
0
    if ( !builder->path_begun )
2019
0
    {
2020
0
      builder->path_begun = 1;
2021
0
      error = cff_builder_add_contour( builder );
2022
0
      if ( !error )
2023
0
        error = cff_builder_add_point1( builder, x, y );
2024
0
    }
2025
2026
0
    return error;
2027
0
  }
2028
2029
2030
  /* close the current contour */
2031
  FT_LOCAL_DEF( void )
2032
  cff_builder_close_contour( CFF_Builder*  builder )
2033
0
  {
2034
0
    FT_Outline*  outline = builder->current;
2035
0
    FT_Int       first;
2036
2037
2038
0
    if ( !outline )
2039
0
      return;
2040
2041
0
    first = outline->n_contours <= 1
2042
0
            ? 0 : outline->contours[outline->n_contours - 2] + 1;
2043
2044
    /* in malformed fonts it can happen that a contour was started */
2045
    /* but no points were added                                    */
2046
0
    if ( outline->n_contours && first == outline->n_points )
2047
0
    {
2048
0
      outline->n_contours--;
2049
0
      return;
2050
0
    }
2051
2052
    /* We must not include the last point in the path if it */
2053
    /* is located on the first point.                       */
2054
0
    if ( outline->n_points > 1 )
2055
0
    {
2056
0
      FT_Vector*  p1      = outline->points + first;
2057
0
      FT_Vector*  p2      = outline->points + outline->n_points - 1;
2058
0
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
2059
2060
2061
      /* `delete' last point only if it coincides with the first    */
2062
      /* point and if it is not a control point (which can happen). */
2063
0
      if ( p1->x == p2->x && p1->y == p2->y )
2064
0
        if ( *control == FT_CURVE_TAG_ON )
2065
0
          outline->n_points--;
2066
0
    }
2067
2068
0
    if ( outline->n_contours > 0 )
2069
0
    {
2070
      /* Don't add contours only consisting of one point, i.e., */
2071
      /* check whether begin point and last point are the same. */
2072
0
      if ( first == outline->n_points - 1 )
2073
0
      {
2074
0
        outline->n_contours--;
2075
0
        outline->n_points--;
2076
0
      }
2077
0
      else
2078
0
        outline->contours[outline->n_contours - 1] =
2079
0
          (short)( outline->n_points - 1 );
2080
0
    }
2081
0
  }
2082
2083
2084
  /*************************************************************************/
2085
  /*************************************************************************/
2086
  /*****                                                               *****/
2087
  /*****                            PS BUILDER                         *****/
2088
  /*****                                                               *****/
2089
  /*************************************************************************/
2090
  /*************************************************************************/
2091
2092
  /**************************************************************************
2093
   *
2094
   * @Function:
2095
   *   ps_builder_init
2096
   *
2097
   * @Description:
2098
   *   Initializes a given glyph builder.
2099
   *
2100
   * @InOut:
2101
   *   builder ::
2102
   *     A pointer to the glyph builder to initialize.
2103
   *
2104
   * @Input:
2105
   *   face ::
2106
   *     The current face object.
2107
   *
2108
   *   size ::
2109
   *     The current size object.
2110
   *
2111
   *   glyph ::
2112
   *     The current glyph object.
2113
   *
2114
   *   hinting ::
2115
   *     Whether hinting should be applied.
2116
   */
2117
  FT_LOCAL_DEF( void )
2118
  ps_builder_init( PS_Builder*  ps_builder,
2119
                   void*        builder,
2120
                   FT_Bool      is_t1 )
2121
0
  {
2122
0
    FT_ZERO( ps_builder );
2123
2124
0
    if ( is_t1 )
2125
0
    {
2126
0
      T1_Builder  t1builder = (T1_Builder)builder;
2127
2128
2129
0
      ps_builder->memory  = t1builder->memory;
2130
0
      ps_builder->face    = (FT_Face)t1builder->face;
2131
0
      ps_builder->glyph   = (CFF_GlyphSlot)t1builder->glyph;
2132
0
      ps_builder->loader  = t1builder->loader;
2133
0
      ps_builder->base    = t1builder->base;
2134
0
      ps_builder->current = t1builder->current;
2135
2136
0
      ps_builder->pos_x = &t1builder->pos_x;
2137
0
      ps_builder->pos_y = &t1builder->pos_y;
2138
2139
0
      ps_builder->left_bearing = &t1builder->left_bearing;
2140
0
      ps_builder->advance      = &t1builder->advance;
2141
2142
0
      ps_builder->bbox        = &t1builder->bbox;
2143
0
      ps_builder->path_begun  = 0;
2144
0
      ps_builder->load_points = t1builder->load_points;
2145
0
      ps_builder->no_recurse  = t1builder->no_recurse;
2146
2147
0
      ps_builder->metrics_only = t1builder->metrics_only;
2148
0
    }
2149
0
    else
2150
0
    {
2151
0
      CFF_Builder*  cffbuilder = (CFF_Builder*)builder;
2152
2153
2154
0
      ps_builder->memory  = cffbuilder->memory;
2155
0
      ps_builder->face    = (FT_Face)cffbuilder->face;
2156
0
      ps_builder->glyph   = cffbuilder->glyph;
2157
0
      ps_builder->loader  = cffbuilder->loader;
2158
0
      ps_builder->base    = cffbuilder->base;
2159
0
      ps_builder->current = cffbuilder->current;
2160
2161
0
      ps_builder->pos_x = &cffbuilder->pos_x;
2162
0
      ps_builder->pos_y = &cffbuilder->pos_y;
2163
2164
0
      ps_builder->left_bearing = &cffbuilder->left_bearing;
2165
0
      ps_builder->advance      = &cffbuilder->advance;
2166
2167
0
      ps_builder->bbox        = &cffbuilder->bbox;
2168
0
      ps_builder->path_begun  = cffbuilder->path_begun;
2169
0
      ps_builder->load_points = cffbuilder->load_points;
2170
0
      ps_builder->no_recurse  = cffbuilder->no_recurse;
2171
2172
0
      ps_builder->metrics_only = cffbuilder->metrics_only;
2173
0
    }
2174
2175
0
    ps_builder->is_t1 = is_t1;
2176
0
    ps_builder->funcs = ps_builder_funcs;
2177
0
  }
2178
2179
2180
  /**************************************************************************
2181
   *
2182
   * @Function:
2183
   *   ps_builder_done
2184
   *
2185
   * @Description:
2186
   *   Finalizes a given glyph builder.  Its contents can still be used
2187
   *   after the call, but the function saves important information
2188
   *   within the corresponding glyph slot.
2189
   *
2190
   * @Input:
2191
   *   builder ::
2192
   *     A pointer to the glyph builder to finalize.
2193
   */
2194
  FT_LOCAL_DEF( void )
2195
  ps_builder_done( PS_Builder*  builder )
2196
0
  {
2197
0
    CFF_GlyphSlot  glyph = builder->glyph;
2198
2199
2200
0
    if ( glyph )
2201
0
      glyph->root.outline = *builder->base;
2202
0
  }
2203
2204
2205
  /* check that there is enough space for `count' more points */
2206
  FT_LOCAL_DEF( FT_Error )
2207
  ps_builder_check_points( PS_Builder*  builder,
2208
                           FT_Int       count )
2209
0
  {
2210
0
    return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
2211
0
  }
2212
2213
2214
  /* add a new point, do not check space */
2215
  FT_LOCAL_DEF( void )
2216
  ps_builder_add_point( PS_Builder*  builder,
2217
                        FT_Pos       x,
2218
                        FT_Pos       y,
2219
                        FT_Byte      flag )
2220
0
  {
2221
0
    FT_Outline*  outline = builder->current;
2222
2223
2224
0
    if ( builder->load_points )
2225
0
    {
2226
0
      FT_Vector*  point   = outline->points + outline->n_points;
2227
0
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
2228
2229
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
2230
      PS_Driver  driver   = (PS_Driver)FT_FACE_DRIVER( builder->face );
2231
2232
2233
      if ( !builder->is_t1 &&
2234
           driver->hinting_engine == FT_HINTING_FREETYPE )
2235
      {
2236
        point->x = x >> 16;
2237
        point->y = y >> 16;
2238
      }
2239
      else
2240
#endif
2241
#ifdef T1_CONFIG_OPTION_OLD_ENGINE
2242
#ifndef CFF_CONFIG_OPTION_OLD_ENGINE
2243
      PS_Driver  driver   = (PS_Driver)FT_FACE_DRIVER( builder->face );
2244
#endif
2245
      if ( builder->is_t1 &&
2246
           driver->hinting_engine == FT_HINTING_FREETYPE )
2247
      {
2248
        point->x = FIXED_TO_INT( x );
2249
        point->y = FIXED_TO_INT( y );
2250
      }
2251
      else
2252
#endif
2253
0
      {
2254
        /* cf2_decoder_parse_charstrings uses 16.16 coordinates */
2255
0
        point->x = x >> 10;
2256
0
        point->y = y >> 10;
2257
0
      }
2258
0
      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
2259
0
    }
2260
0
    outline->n_points++;
2261
0
  }
2262
2263
2264
  /* check space for a new on-curve point, then add it */
2265
  FT_LOCAL_DEF( FT_Error )
2266
  ps_builder_add_point1( PS_Builder*  builder,
2267
                         FT_Pos       x,
2268
                         FT_Pos       y )
2269
0
  {
2270
0
    FT_Error  error;
2271
2272
2273
0
    error = ps_builder_check_points( builder, 1 );
2274
0
    if ( !error )
2275
0
      ps_builder_add_point( builder, x, y, 1 );
2276
2277
0
    return error;
2278
0
  }
2279
2280
2281
  /* check space for a new contour, then add it */
2282
  FT_LOCAL_DEF( FT_Error )
2283
  ps_builder_add_contour( PS_Builder*  builder )
2284
0
  {
2285
0
    FT_Outline*  outline = builder->current;
2286
0
    FT_Error     error;
2287
2288
2289
    /* this might happen in invalid fonts */
2290
0
    if ( !outline )
2291
0
    {
2292
0
      FT_ERROR(( "ps_builder_add_contour: no outline to add points to\n" ));
2293
0
      return FT_THROW( Invalid_File_Format );
2294
0
    }
2295
2296
0
    if ( !builder->load_points )
2297
0
    {
2298
0
      outline->n_contours++;
2299
0
      return FT_Err_Ok;
2300
0
    }
2301
2302
0
    error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
2303
0
    if ( !error )
2304
0
    {
2305
0
      if ( outline->n_contours > 0 )
2306
0
        outline->contours[outline->n_contours - 1] =
2307
0
          (short)( outline->n_points - 1 );
2308
2309
0
      outline->n_contours++;
2310
0
    }
2311
2312
0
    return error;
2313
0
  }
2314
2315
2316
  /* if a path was begun, add its first on-curve point */
2317
  FT_LOCAL_DEF( FT_Error )
2318
  ps_builder_start_point( PS_Builder*  builder,
2319
                          FT_Pos       x,
2320
                          FT_Pos       y )
2321
0
  {
2322
0
    FT_Error  error = FT_Err_Ok;
2323
2324
2325
    /* test whether we are building a new contour */
2326
0
    if ( !builder->path_begun )
2327
0
    {
2328
0
      builder->path_begun = 1;
2329
0
      error = ps_builder_add_contour( builder );
2330
0
      if ( !error )
2331
0
        error = ps_builder_add_point1( builder, x, y );
2332
0
    }
2333
2334
0
    return error;
2335
0
  }
2336
2337
2338
  /* close the current contour */
2339
  FT_LOCAL_DEF( void )
2340
  ps_builder_close_contour( PS_Builder*  builder )
2341
0
  {
2342
0
    FT_Outline*  outline = builder->current;
2343
0
    FT_Int       first;
2344
2345
2346
0
    if ( !outline )
2347
0
      return;
2348
2349
0
    first = outline->n_contours <= 1
2350
0
            ? 0 : outline->contours[outline->n_contours - 2] + 1;
2351
2352
    /* in malformed fonts it can happen that a contour was started */
2353
    /* but no points were added                                    */
2354
0
    if ( outline->n_contours && first == outline->n_points )
2355
0
    {
2356
0
      outline->n_contours--;
2357
0
      return;
2358
0
    }
2359
2360
    /* We must not include the last point in the path if it */
2361
    /* is located on the first point.                       */
2362
0
    if ( outline->n_points > 1 )
2363
0
    {
2364
0
      FT_Vector*  p1      = outline->points + first;
2365
0
      FT_Vector*  p2      = outline->points + outline->n_points - 1;
2366
0
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
2367
2368
2369
      /* `delete' last point only if it coincides with the first */
2370
      /* point and it is not a control point (which can happen). */
2371
0
      if ( p1->x == p2->x && p1->y == p2->y )
2372
0
        if ( *control == FT_CURVE_TAG_ON )
2373
0
          outline->n_points--;
2374
0
    }
2375
2376
0
    if ( outline->n_contours > 0 )
2377
0
    {
2378
      /* Don't add contours only consisting of one point, i.e.,  */
2379
      /* check whether the first and the last point is the same. */
2380
0
      if ( first == outline->n_points - 1 )
2381
0
      {
2382
0
        outline->n_contours--;
2383
0
        outline->n_points--;
2384
0
      }
2385
0
      else
2386
0
        outline->contours[outline->n_contours - 1] =
2387
0
          (short)( outline->n_points - 1 );
2388
0
    }
2389
0
  }
2390
2391
2392
  /*************************************************************************/
2393
  /*************************************************************************/
2394
  /*****                                                               *****/
2395
  /*****                            OTHER                              *****/
2396
  /*****                                                               *****/
2397
  /*************************************************************************/
2398
  /*************************************************************************/
2399
2400
2401
  /**************************************************************************
2402
   *
2403
   * @Function:
2404
   *   ps_decoder_init
2405
   *
2406
   * @Description:
2407
   *   Creates a wrapper decoder for use in the combined
2408
   *   Type 1 / CFF interpreter.
2409
   *
2410
   * @InOut:
2411
   *   ps_decoder ::
2412
   *     A pointer to the decoder to initialize.
2413
   *
2414
   * @Input:
2415
   *   decoder ::
2416
   *     A pointer to the original decoder.
2417
   *
2418
   *   is_t1 ::
2419
   *     Flag indicating Type 1 or CFF
2420
   */
2421
  FT_LOCAL_DEF( void )
2422
  ps_decoder_init( PS_Decoder*  ps_decoder,
2423
                   void*        decoder,
2424
                   FT_Bool      is_t1 )
2425
0
  {
2426
0
    FT_ZERO( ps_decoder );
2427
2428
0
    if ( is_t1 )
2429
0
    {
2430
0
      T1_Decoder  t1_decoder = (T1_Decoder)decoder;
2431
2432
2433
0
      ps_builder_init( &ps_decoder->builder,
2434
0
                       &t1_decoder->builder,
2435
0
                       is_t1 );
2436
2437
0
      ps_decoder->cf2_instance = &t1_decoder->cf2_instance;
2438
0
      ps_decoder->psnames      = t1_decoder->psnames;
2439
2440
0
      ps_decoder->num_glyphs  = t1_decoder->num_glyphs;
2441
0
      ps_decoder->glyph_names = t1_decoder->glyph_names;
2442
0
      ps_decoder->hint_mode   = t1_decoder->hint_mode;
2443
0
      ps_decoder->blend       = t1_decoder->blend;
2444
2445
0
      ps_decoder->num_locals  = (FT_UInt)t1_decoder->num_subrs;
2446
0
      ps_decoder->locals      = t1_decoder->subrs;
2447
0
      ps_decoder->locals_len  = t1_decoder->subrs_len;
2448
0
      ps_decoder->locals_hash = t1_decoder->subrs_hash;
2449
2450
0
      ps_decoder->buildchar     = t1_decoder->buildchar;
2451
0
      ps_decoder->len_buildchar = t1_decoder->len_buildchar;
2452
2453
0
      ps_decoder->lenIV = t1_decoder->lenIV;
2454
0
    }
2455
0
    else
2456
0
    {
2457
0
      CFF_Decoder*  cff_decoder = (CFF_Decoder*)decoder;
2458
2459
2460
0
      ps_builder_init( &ps_decoder->builder,
2461
0
                       &cff_decoder->builder,
2462
0
                       is_t1 );
2463
2464
0
      ps_decoder->cff             = cff_decoder->cff;
2465
0
      ps_decoder->cf2_instance    = &cff_decoder->cff->cf2_instance;
2466
0
      ps_decoder->current_subfont = cff_decoder->current_subfont;
2467
2468
0
      ps_decoder->num_globals  = cff_decoder->num_globals;
2469
0
      ps_decoder->globals      = cff_decoder->globals;
2470
0
      ps_decoder->globals_bias = cff_decoder->globals_bias;
2471
0
      ps_decoder->num_locals   = cff_decoder->num_locals;
2472
0
      ps_decoder->locals       = cff_decoder->locals;
2473
0
      ps_decoder->locals_bias  = cff_decoder->locals_bias;
2474
2475
0
      ps_decoder->glyph_width   = &cff_decoder->glyph_width;
2476
0
      ps_decoder->width_only    = cff_decoder->width_only;
2477
2478
0
      ps_decoder->hint_mode = cff_decoder->hint_mode;
2479
2480
0
      ps_decoder->get_glyph_callback  = cff_decoder->get_glyph_callback;
2481
0
      ps_decoder->free_glyph_callback = cff_decoder->free_glyph_callback;
2482
0
    }
2483
0
  }
2484
2485
2486
  /* Synthesize a SubFont object for Type 1 fonts, for use in the  */
2487
  /* new interpreter to access Private dict data.                  */
2488
  FT_LOCAL_DEF( void )
2489
  t1_make_subfont( FT_Face      face,
2490
                   PS_Private   priv,
2491
                   CFF_SubFont  subfont )
2492
0
  {
2493
0
    CFF_Private  cpriv = &subfont->private_dict;
2494
0
    FT_UInt      n, count;
2495
2496
2497
0
    FT_ZERO( subfont );
2498
0
    FT_ZERO( cpriv );
2499
2500
0
    count = cpriv->num_blue_values = priv->num_blue_values;
2501
0
    for ( n = 0; n < count; n++ )
2502
0
      cpriv->blue_values[n] = (FT_Pos)priv->blue_values[n];
2503
2504
0
    count = cpriv->num_other_blues = priv->num_other_blues;
2505
0
    for ( n = 0; n < count; n++ )
2506
0
      cpriv->other_blues[n] = (FT_Pos)priv->other_blues[n];
2507
2508
0
    count = cpriv->num_family_blues = priv->num_family_blues;
2509
0
    for ( n = 0; n < count; n++ )
2510
0
      cpriv->family_blues[n] = (FT_Pos)priv->family_blues[n];
2511
2512
0
    count = cpriv->num_family_other_blues = priv->num_family_other_blues;
2513
0
    for ( n = 0; n < count; n++ )
2514
0
      cpriv->family_other_blues[n] = (FT_Pos)priv->family_other_blues[n];
2515
2516
0
    cpriv->blue_scale = priv->blue_scale;
2517
0
    cpriv->blue_shift = (FT_Pos)priv->blue_shift;
2518
0
    cpriv->blue_fuzz  = (FT_Pos)priv->blue_fuzz;
2519
2520
0
    cpriv->standard_width  = (FT_Pos)priv->standard_width[0];
2521
0
    cpriv->standard_height = (FT_Pos)priv->standard_height[0];
2522
2523
0
    count = cpriv->num_snap_widths = priv->num_snap_widths;
2524
0
    for ( n = 0; n < count; n++ )
2525
0
      cpriv->snap_widths[n] = (FT_Pos)priv->snap_widths[n];
2526
2527
0
    count = cpriv->num_snap_heights = priv->num_snap_heights;
2528
0
    for ( n = 0; n < count; n++ )
2529
0
      cpriv->snap_heights[n] = (FT_Pos)priv->snap_heights[n];
2530
2531
0
    cpriv->force_bold       = priv->force_bold;
2532
0
    cpriv->lenIV            = priv->lenIV;
2533
0
    cpriv->language_group   = priv->language_group;
2534
0
    cpriv->expansion_factor = priv->expansion_factor;
2535
2536
0
    cpriv->subfont = subfont;
2537
2538
2539
    /* Initialize the random number generator. */
2540
0
    if ( face->internal->random_seed != -1 )
2541
0
    {
2542
      /* If we have a face-specific seed, use it.    */
2543
      /* If non-zero, update it to a positive value. */
2544
0
      subfont->random = (FT_UInt32)face->internal->random_seed;
2545
0
      if ( face->internal->random_seed )
2546
0
      {
2547
0
        do
2548
0
        {
2549
0
          face->internal->random_seed = (FT_Int32)cff_random(
2550
0
            (FT_UInt32)face->internal->random_seed );
2551
2552
0
        } while ( face->internal->random_seed < 0 );
2553
0
      }
2554
0
    }
2555
0
    if ( !subfont->random )
2556
0
    {
2557
0
      FT_UInt32  seed;
2558
2559
2560
      /* compute random seed from some memory addresses */
2561
0
      seed = (FT_UInt32)( (FT_Offset)(char*)&seed    ^
2562
0
                          (FT_Offset)(char*)&face    ^
2563
0
                          (FT_Offset)(char*)&subfont );
2564
0
      seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 );
2565
0
      if ( seed == 0 )
2566
0
        seed = 0x7384;
2567
2568
0
      subfont->random = seed;
2569
0
    }
2570
0
  }
2571
2572
2573
  FT_LOCAL_DEF( void )
2574
  t1_decrypt( FT_Byte*   buffer,
2575
              FT_Offset  length,
2576
              FT_UShort  seed )
2577
0
  {
2578
0
    PS_Conv_EexecDecode( &buffer,
2579
0
                         FT_OFFSET( buffer, length ),
2580
0
                         buffer,
2581
0
                         length,
2582
0
                         &seed );
2583
0
  }
2584
2585
2586
  FT_LOCAL_DEF( FT_UInt32 )
2587
  cff_random( FT_UInt32  r )
2588
4.32k
  {
2589
    /* a 32bit version of the `xorshift' algorithm */
2590
4.32k
    r ^= r << 13;
2591
4.32k
    r ^= r >> 17;
2592
4.32k
    r ^= r << 5;
2593
2594
4.32k
    return r;
2595
4.32k
  }
2596
2597
2598
/* END */