Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3918 Serge 1
/***************************************************************************/
2
/*                                                                         */
3
/*  ftstream.c                                                             */
4
/*                                                                         */
5
/*    I/O stream support (body).                                           */
6
/*                                                                         */
7
/*  Copyright 2000-2002, 2004-2006, 2008-2011, 2013 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 
20
#include FT_INTERNAL_STREAM_H
21
#include FT_INTERNAL_DEBUG_H
22
 
23
 
24
  /*************************************************************************/
25
  /*                                                                       */
26
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
27
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
28
  /* messages during execution.                                            */
29
  /*                                                                       */
30
#undef  FT_COMPONENT
31
#define FT_COMPONENT  trace_stream
32
 
33
 
34
  FT_BASE_DEF( void )
35
  FT_Stream_OpenMemory( FT_Stream       stream,
36
                        const FT_Byte*  base,
37
                        FT_ULong        size )
38
  {
39
    stream->base   = (FT_Byte*) base;
40
    stream->size   = size;
41
    stream->pos    = 0;
42
    stream->cursor = 0;
43
    stream->read   = 0;
44
    stream->close  = 0;
45
  }
46
 
47
 
48
  FT_BASE_DEF( void )
49
  FT_Stream_Close( FT_Stream  stream )
50
  {
51
    if ( stream && stream->close )
52
      stream->close( stream );
53
  }
54
 
55
 
56
  FT_BASE_DEF( FT_Error )
57
  FT_Stream_Seek( FT_Stream  stream,
58
                  FT_ULong   pos )
59
  {
60
    FT_Error  error = FT_Err_Ok;
61
 
62
 
63
    if ( stream->read )
64
    {
65
      if ( stream->read( stream, pos, 0, 0 ) )
66
      {
67
        FT_ERROR(( "FT_Stream_Seek:"
68
                   " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
69
                   pos, stream->size ));
70
 
71
        error = FT_THROW( Invalid_Stream_Operation );
72
      }
73
    }
74
    /* note that seeking to the first position after the file is valid */
75
    else if ( pos > stream->size )
76
    {
77
      FT_ERROR(( "FT_Stream_Seek:"
78
                 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
79
                 pos, stream->size ));
80
 
81
      error = FT_THROW( Invalid_Stream_Operation );
82
    }
83
 
84
    if ( !error )
85
      stream->pos = pos;
86
 
87
    return error;
88
  }
89
 
90
 
91
  FT_BASE_DEF( FT_Error )
92
  FT_Stream_Skip( FT_Stream  stream,
93
                  FT_Long    distance )
94
  {
95
    if ( distance < 0 )
96
      return FT_THROW( Invalid_Stream_Operation );
97
 
98
    return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) );
99
  }
100
 
101
 
102
  FT_BASE_DEF( FT_Long )
103
  FT_Stream_Pos( FT_Stream  stream )
104
  {
105
    return stream->pos;
106
  }
107
 
108
 
109
  FT_BASE_DEF( FT_Error )
110
  FT_Stream_Read( FT_Stream  stream,
111
                  FT_Byte*   buffer,
112
                  FT_ULong   count )
113
  {
114
    return FT_Stream_ReadAt( stream, stream->pos, buffer, count );
115
  }
116
 
117
 
118
  FT_BASE_DEF( FT_Error )
119
  FT_Stream_ReadAt( FT_Stream  stream,
120
                    FT_ULong   pos,
121
                    FT_Byte*   buffer,
122
                    FT_ULong   count )
123
  {
124
    FT_Error  error = FT_Err_Ok;
125
    FT_ULong  read_bytes;
126
 
127
 
128
    if ( pos >= stream->size )
129
    {
130
      FT_ERROR(( "FT_Stream_ReadAt:"
131
                 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
132
                 pos, stream->size ));
133
 
134
      return FT_THROW( Invalid_Stream_Operation );
135
    }
136
 
137
    if ( stream->read )
138
      read_bytes = stream->read( stream, pos, buffer, count );
139
    else
140
    {
141
      read_bytes = stream->size - pos;
142
      if ( read_bytes > count )
143
        read_bytes = count;
144
 
145
      FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
146
    }
147
 
148
    stream->pos = pos + read_bytes;
149
 
150
    if ( read_bytes < count )
151
    {
152
      FT_ERROR(( "FT_Stream_ReadAt:"
153
                 " invalid read; expected %lu bytes, got %lu\n",
154
                 count, read_bytes ));
155
 
156
      error = FT_THROW( Invalid_Stream_Operation );
157
    }
158
 
159
    return error;
160
  }
161
 
162
 
163
  FT_BASE_DEF( FT_ULong )
164
  FT_Stream_TryRead( FT_Stream  stream,
165
                     FT_Byte*   buffer,
166
                     FT_ULong   count )
167
  {
168
    FT_ULong  read_bytes = 0;
169
 
170
 
171
    if ( stream->pos >= stream->size )
172
      goto Exit;
173
 
174
    if ( stream->read )
175
      read_bytes = stream->read( stream, stream->pos, buffer, count );
176
    else
177
    {
178
      read_bytes = stream->size - stream->pos;
179
      if ( read_bytes > count )
180
        read_bytes = count;
181
 
182
      FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
183
    }
184
 
185
    stream->pos += read_bytes;
186
 
187
  Exit:
188
    return read_bytes;
189
  }
190
 
191
 
192
  FT_BASE_DEF( FT_Error )
193
  FT_Stream_ExtractFrame( FT_Stream  stream,
194
                          FT_ULong   count,
195
                          FT_Byte**  pbytes )
196
  {
197
    FT_Error  error;
198
 
199
 
200
    error = FT_Stream_EnterFrame( stream, count );
201
    if ( !error )
202
    {
203
      *pbytes = (FT_Byte*)stream->cursor;
204
 
205
      /* equivalent to FT_Stream_ExitFrame(), with no memory block release */
206
      stream->cursor = 0;
207
      stream->limit  = 0;
208
    }
209
 
210
    return error;
211
  }
212
 
213
 
214
  FT_BASE_DEF( void )
215
  FT_Stream_ReleaseFrame( FT_Stream  stream,
216
                          FT_Byte**  pbytes )
217
  {
218
    if ( stream && stream->read )
219
    {
220
      FT_Memory  memory = stream->memory;
221
 
222
#ifdef FT_DEBUG_MEMORY
223
      ft_mem_free( memory, *pbytes );
224
      *pbytes = NULL;
225
#else
226
      FT_FREE( *pbytes );
227
#endif
228
    }
229
    *pbytes = 0;
230
  }
231
 
232
 
233
  FT_BASE_DEF( FT_Error )
234
  FT_Stream_EnterFrame( FT_Stream  stream,
235
                        FT_ULong   count )
236
  {
237
    FT_Error  error = FT_Err_Ok;
238
    FT_ULong  read_bytes;
239
 
240
 
241
    /* check for nested frame access */
242
    FT_ASSERT( stream && stream->cursor == 0 );
243
 
244
    if ( stream->read )
245
    {
246
      /* allocate the frame in memory */
247
      FT_Memory  memory = stream->memory;
248
 
249
 
250
      /* simple sanity check */
251
      if ( count > stream->size )
252
      {
253
        FT_ERROR(( "FT_Stream_EnterFrame:"
254
                   " frame size (%lu) larger than stream size (%lu)\n",
255
                   count, stream->size ));
256
 
257
        error = FT_THROW( Invalid_Stream_Operation );
258
        goto Exit;
259
      }
260
 
261
#ifdef FT_DEBUG_MEMORY
262
      /* assume _ft_debug_file and _ft_debug_lineno are already set */
263
      stream->base = (unsigned char*)ft_mem_qalloc( memory, count, &error );
264
      if ( error )
265
        goto Exit;
266
#else
267
      if ( FT_QALLOC( stream->base, count ) )
268
        goto Exit;
269
#endif
270
      /* read it */
271
      read_bytes = stream->read( stream, stream->pos,
272
                                 stream->base, count );
273
      if ( read_bytes < count )
274
      {
275
        FT_ERROR(( "FT_Stream_EnterFrame:"
276
                   " invalid read; expected %lu bytes, got %lu\n",
277
                   count, read_bytes ));
278
 
279
        FT_FREE( stream->base );
280
        error = FT_THROW( Invalid_Stream_Operation );
281
      }
282
      stream->cursor = stream->base;
283
      stream->limit  = stream->cursor + count;
284
      stream->pos   += read_bytes;
285
    }
286
    else
287
    {
288
      /* check current and new position */
289
      if ( stream->pos >= stream->size        ||
290
           stream->size - stream->pos < count )
291
      {
292
        FT_ERROR(( "FT_Stream_EnterFrame:"
293
                   " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
294
                   stream->pos, count, stream->size ));
295
 
296
        error = FT_THROW( Invalid_Stream_Operation );
297
        goto Exit;
298
      }
299
 
300
      /* set cursor */
301
      stream->cursor = stream->base + stream->pos;
302
      stream->limit  = stream->cursor + count;
303
      stream->pos   += count;
304
    }
305
 
306
  Exit:
307
    return error;
308
  }
309
 
310
 
311
  FT_BASE_DEF( void )
312
  FT_Stream_ExitFrame( FT_Stream  stream )
313
  {
314
    /* IMPORTANT: The assertion stream->cursor != 0 was removed, given    */
315
    /*            that it is possible to access a frame of length 0 in    */
316
    /*            some weird fonts (usually, when accessing an array of   */
317
    /*            0 records, like in some strange kern tables).           */
318
    /*                                                                    */
319
    /*  In this case, the loader code handles the 0-length table          */
320
    /*  gracefully; however, stream.cursor is really set to 0 by the      */
321
    /*  FT_Stream_EnterFrame() call, and this is not an error.            */
322
    /*                                                                    */
323
    FT_ASSERT( stream );
324
 
325
    if ( stream->read )
326
    {
327
      FT_Memory  memory = stream->memory;
328
 
329
#ifdef FT_DEBUG_MEMORY
330
      ft_mem_free( memory, stream->base );
331
      stream->base = NULL;
332
#else
333
      FT_FREE( stream->base );
334
#endif
335
    }
336
    stream->cursor = 0;
337
    stream->limit  = 0;
338
  }
339
 
340
 
341
  FT_BASE_DEF( FT_Char )
342
  FT_Stream_GetChar( FT_Stream  stream )
343
  {
344
    FT_Char  result;
345
 
346
 
347
    FT_ASSERT( stream && stream->cursor );
348
 
349
    result = 0;
350
    if ( stream->cursor < stream->limit )
351
      result = *stream->cursor++;
352
 
353
    return result;
354
  }
355
 
356
 
357
  FT_BASE_DEF( FT_UShort )
358
  FT_Stream_GetUShort( FT_Stream  stream )
359
  {
360
    FT_Byte*  p;
361
    FT_Short  result;
362
 
363
 
364
    FT_ASSERT( stream && stream->cursor );
365
 
366
    result         = 0;
367
    p              = stream->cursor;
368
    if ( p + 1 < stream->limit )
369
      result       = FT_NEXT_USHORT( p );
370
    stream->cursor = p;
371
 
372
    return result;
373
  }
374
 
375
 
376
  FT_BASE_DEF( FT_UShort )
377
  FT_Stream_GetUShortLE( FT_Stream  stream )
378
  {
379
    FT_Byte*  p;
380
    FT_Short  result;
381
 
382
 
383
    FT_ASSERT( stream && stream->cursor );
384
 
385
    result         = 0;
386
    p              = stream->cursor;
387
    if ( p + 1 < stream->limit )
388
      result       = FT_NEXT_USHORT_LE( p );
389
    stream->cursor = p;
390
 
391
    return result;
392
  }
393
 
394
 
395
  FT_BASE_DEF( FT_ULong )
396
  FT_Stream_GetUOffset( FT_Stream  stream )
397
  {
398
    FT_Byte*  p;
399
    FT_Long   result;
400
 
401
 
402
    FT_ASSERT( stream && stream->cursor );
403
 
404
    result         = 0;
405
    p              = stream->cursor;
406
    if ( p + 2 < stream->limit )
407
      result       = FT_NEXT_UOFF3( p );
408
    stream->cursor = p;
409
    return result;
410
  }
411
 
412
 
413
  FT_BASE_DEF( FT_ULong )
414
  FT_Stream_GetULong( FT_Stream  stream )
415
  {
416
    FT_Byte*  p;
417
    FT_Long   result;
418
 
419
 
420
    FT_ASSERT( stream && stream->cursor );
421
 
422
    result         = 0;
423
    p              = stream->cursor;
424
    if ( p + 3 < stream->limit )
425
      result       = FT_NEXT_ULONG( p );
426
    stream->cursor = p;
427
    return result;
428
  }
429
 
430
 
431
  FT_BASE_DEF( FT_ULong )
432
  FT_Stream_GetULongLE( FT_Stream  stream )
433
  {
434
    FT_Byte*  p;
435
    FT_Long   result;
436
 
437
 
438
    FT_ASSERT( stream && stream->cursor );
439
 
440
    result         = 0;
441
    p              = stream->cursor;
442
    if ( p + 3 < stream->limit )
443
      result       = FT_NEXT_ULONG_LE( p );
444
    stream->cursor = p;
445
    return result;
446
  }
447
 
448
 
449
  FT_BASE_DEF( FT_Char )
450
  FT_Stream_ReadChar( FT_Stream  stream,
451
                      FT_Error*  error )
452
  {
453
    FT_Byte  result = 0;
454
 
455
 
456
    FT_ASSERT( stream );
457
 
458
    *error = FT_Err_Ok;
459
 
460
    if ( stream->read )
461
    {
462
      if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
463
        goto Fail;
464
    }
465
    else
466
    {
467
      if ( stream->pos < stream->size )
468
        result = stream->base[stream->pos];
469
      else
470
        goto Fail;
471
    }
472
    stream->pos++;
473
 
474
    return result;
475
 
476
  Fail:
477
    *error = FT_THROW( Invalid_Stream_Operation );
478
    FT_ERROR(( "FT_Stream_ReadChar:"
479
               " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
480
               stream->pos, stream->size ));
481
 
482
    return 0;
483
  }
484
 
485
 
486
  FT_BASE_DEF( FT_UShort )
487
  FT_Stream_ReadUShort( FT_Stream  stream,
488
                       FT_Error*  error )
489
  {
490
    FT_Byte   reads[2];
491
    FT_Byte*  p = 0;
492
    FT_Short  result = 0;
493
 
494
 
495
    FT_ASSERT( stream );
496
 
497
    *error = FT_Err_Ok;
498
 
499
    if ( stream->pos + 1 < stream->size )
500
    {
501
      if ( stream->read )
502
      {
503
        if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
504
          goto Fail;
505
 
506
        p = reads;
507
      }
508
      else
509
      {
510
        p = stream->base + stream->pos;
511
      }
512
 
513
      if ( p )
514
        result = FT_NEXT_USHORT( p );
515
    }
516
    else
517
      goto Fail;
518
 
519
    stream->pos += 2;
520
 
521
    return result;
522
 
523
  Fail:
524
    *error = FT_THROW( Invalid_Stream_Operation );
525
    FT_ERROR(( "FT_Stream_ReadUShort:"
526
               " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
527
               stream->pos, stream->size ));
528
 
529
    return 0;
530
  }
531
 
532
 
533
  FT_BASE_DEF( FT_UShort )
534
  FT_Stream_ReadUShortLE( FT_Stream  stream,
535
                         FT_Error*  error )
536
  {
537
    FT_Byte   reads[2];
538
    FT_Byte*  p = 0;
539
    FT_Short  result = 0;
540
 
541
 
542
    FT_ASSERT( stream );
543
 
544
    *error = FT_Err_Ok;
545
 
546
    if ( stream->pos + 1 < stream->size )
547
    {
548
      if ( stream->read )
549
      {
550
        if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
551
          goto Fail;
552
 
553
        p = reads;
554
      }
555
      else
556
      {
557
        p = stream->base + stream->pos;
558
      }
559
 
560
      if ( p )
561
        result = FT_NEXT_USHORT_LE( p );
562
    }
563
    else
564
      goto Fail;
565
 
566
    stream->pos += 2;
567
 
568
    return result;
569
 
570
  Fail:
571
    *error = FT_THROW( Invalid_Stream_Operation );
572
    FT_ERROR(( "FT_Stream_ReadUShortLE:"
573
               " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
574
               stream->pos, stream->size ));
575
 
576
    return 0;
577
  }
578
 
579
 
580
  FT_BASE_DEF( FT_ULong )
581
  FT_Stream_ReadUOffset( FT_Stream  stream,
582
                        FT_Error*  error )
583
  {
584
    FT_Byte   reads[3];
585
    FT_Byte*  p = 0;
586
    FT_Long   result = 0;
587
 
588
 
589
    FT_ASSERT( stream );
590
 
591
    *error = FT_Err_Ok;
592
 
593
    if ( stream->pos + 2 < stream->size )
594
    {
595
      if ( stream->read )
596
      {
597
        if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
598
          goto Fail;
599
 
600
        p = reads;
601
      }
602
      else
603
      {
604
        p = stream->base + stream->pos;
605
      }
606
 
607
      if ( p )
608
        result = FT_NEXT_UOFF3( p );
609
    }
610
    else
611
      goto Fail;
612
 
613
    stream->pos += 3;
614
 
615
    return result;
616
 
617
  Fail:
618
    *error = FT_THROW( Invalid_Stream_Operation );
619
    FT_ERROR(( "FT_Stream_ReadUOffset:"
620
               " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
621
               stream->pos, stream->size ));
622
 
623
    return 0;
624
  }
625
 
626
 
627
  FT_BASE_DEF( FT_ULong )
628
  FT_Stream_ReadULong( FT_Stream  stream,
629
                      FT_Error*  error )
630
  {
631
    FT_Byte   reads[4];
632
    FT_Byte*  p = 0;
633
    FT_Long   result = 0;
634
 
635
 
636
    FT_ASSERT( stream );
637
 
638
    *error = FT_Err_Ok;
639
 
640
    if ( stream->pos + 3 < stream->size )
641
    {
642
      if ( stream->read )
643
      {
644
        if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
645
          goto Fail;
646
 
647
        p = reads;
648
      }
649
      else
650
      {
651
        p = stream->base + stream->pos;
652
      }
653
 
654
      if ( p )
655
        result = FT_NEXT_ULONG( p );
656
    }
657
    else
658
      goto Fail;
659
 
660
    stream->pos += 4;
661
 
662
    return result;
663
 
664
  Fail:
665
    *error = FT_THROW( Invalid_Stream_Operation );
666
    FT_ERROR(( "FT_Stream_ReadULong:"
667
               " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
668
               stream->pos, stream->size ));
669
 
670
    return 0;
671
  }
672
 
673
 
674
  FT_BASE_DEF( FT_ULong )
675
  FT_Stream_ReadULongLE( FT_Stream  stream,
676
                        FT_Error*  error )
677
  {
678
    FT_Byte   reads[4];
679
    FT_Byte*  p = 0;
680
    FT_Long   result = 0;
681
 
682
 
683
    FT_ASSERT( stream );
684
 
685
    *error = FT_Err_Ok;
686
 
687
    if ( stream->pos + 3 < stream->size )
688
    {
689
      if ( stream->read )
690
      {
691
        if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
692
          goto Fail;
693
 
694
        p = reads;
695
      }
696
      else
697
      {
698
        p = stream->base + stream->pos;
699
      }
700
 
701
      if ( p )
702
        result = FT_NEXT_ULONG_LE( p );
703
    }
704
    else
705
      goto Fail;
706
 
707
    stream->pos += 4;
708
 
709
    return result;
710
 
711
  Fail:
712
    *error = FT_THROW( Invalid_Stream_Operation );
713
    FT_ERROR(( "FT_Stream_ReadULongLE:"
714
               " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
715
               stream->pos, stream->size ));
716
 
717
    return 0;
718
  }
719
 
720
 
721
  FT_BASE_DEF( FT_Error )
722
  FT_Stream_ReadFields( FT_Stream              stream,
723
                        const FT_Frame_Field*  fields,
724
                        void*                  structure )
725
  {
726
    FT_Error  error;
727
    FT_Bool   frame_accessed = 0;
728
    FT_Byte*  cursor;
729
 
730
 
731
    if ( !fields || !stream )
732
      return FT_THROW( Invalid_Argument );
733
 
734
    cursor = stream->cursor;
735
 
736
    error = FT_Err_Ok;
737
    do
738
    {
739
      FT_ULong  value;
740
      FT_Int    sign_shift;
741
      FT_Byte*  p;
742
 
743
 
744
      switch ( fields->value )
745
      {
746
      case ft_frame_start:  /* access a new frame */
747
        error = FT_Stream_EnterFrame( stream, fields->offset );
748
        if ( error )
749
          goto Exit;
750
 
751
        frame_accessed = 1;
752
        cursor         = stream->cursor;
753
        fields++;
754
        continue;  /* loop! */
755
 
756
      case ft_frame_bytes:  /* read a byte sequence */
757
      case ft_frame_skip:   /* skip some bytes      */
758
        {
759
          FT_UInt  len = fields->size;
760
 
761
 
762
          if ( cursor + len > stream->limit )
763
          {
764
            error = FT_THROW( Invalid_Stream_Operation );
765
            goto Exit;
766
          }
767
 
768
          if ( fields->value == ft_frame_bytes )
769
          {
770
            p = (FT_Byte*)structure + fields->offset;
771
            FT_MEM_COPY( p, cursor, len );
772
          }
773
          cursor += len;
774
          fields++;
775
          continue;
776
        }
777
 
778
      case ft_frame_byte:
779
      case ft_frame_schar:  /* read a single byte */
780
        value = FT_NEXT_BYTE( cursor );
781
        sign_shift = 24;
782
        break;
783
 
784
      case ft_frame_short_be:
785
      case ft_frame_ushort_be:  /* read a 2-byte big-endian short */
786
        value = FT_NEXT_USHORT( cursor) ;
787
        sign_shift = 16;
788
        break;
789
 
790
      case ft_frame_short_le:
791
      case ft_frame_ushort_le:  /* read a 2-byte little-endian short */
792
        value = FT_NEXT_USHORT_LE( cursor );
793
        sign_shift = 16;
794
        break;
795
 
796
      case ft_frame_long_be:
797
      case ft_frame_ulong_be:  /* read a 4-byte big-endian long */
798
        value = FT_NEXT_ULONG( cursor );
799
        sign_shift = 0;
800
        break;
801
 
802
      case ft_frame_long_le:
803
      case ft_frame_ulong_le:  /* read a 4-byte little-endian long */
804
        value = FT_NEXT_ULONG_LE( cursor );
805
        sign_shift = 0;
806
        break;
807
 
808
      case ft_frame_off3_be:
809
      case ft_frame_uoff3_be:  /* read a 3-byte big-endian long */
810
        value = FT_NEXT_UOFF3( cursor );
811
        sign_shift = 8;
812
        break;
813
 
814
      case ft_frame_off3_le:
815
      case ft_frame_uoff3_le:  /* read a 3-byte little-endian long */
816
        value = FT_NEXT_UOFF3_LE( cursor );
817
        sign_shift = 8;
818
        break;
819
 
820
      default:
821
        /* otherwise, exit the loop */
822
        stream->cursor = cursor;
823
        goto Exit;
824
      }
825
 
826
      /* now, compute the signed value is necessary */
827
      if ( fields->value & FT_FRAME_OP_SIGNED )
828
        value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
829
 
830
      /* finally, store the value in the object */
831
 
832
      p = (FT_Byte*)structure + fields->offset;
833
      switch ( fields->size )
834
      {
835
      case ( 8 / FT_CHAR_BIT ):
836
        *(FT_Byte*)p = (FT_Byte)value;
837
        break;
838
 
839
      case ( 16 / FT_CHAR_BIT ):
840
        *(FT_UShort*)p = (FT_UShort)value;
841
        break;
842
 
843
      case ( 32 / FT_CHAR_BIT ):
844
        *(FT_UInt32*)p = (FT_UInt32)value;
845
        break;
846
 
847
      default:  /* for 64-bit systems */
848
        *(FT_ULong*)p = (FT_ULong)value;
849
      }
850
 
851
      /* go to next field */
852
      fields++;
853
    }
854
    while ( 1 );
855
 
856
  Exit:
857
    /* close the frame if it was opened by this read */
858
    if ( frame_accessed )
859
      FT_Stream_ExitFrame( stream );
860
 
861
    return error;
862
  }
863
 
864
 
865
/* END */