• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftstream.c                                                             */
4 /*                                                                         */
5 /*    I/O stream support (body).                                           */
6 /*                                                                         */
7 /*  Copyright 2000-2002, 2004-2006, 2008-2011 by                           */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17 
18 
19 #include <ft2build.h>
20 #include FT_INTERNAL_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 )
FT_Stream_OpenMemory(FT_Stream stream,const FT_Byte * base,FT_ULong size)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 )
FT_Stream_Close(FT_Stream stream)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 )
FT_Stream_Seek(FT_Stream stream,FT_ULong pos)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_Err_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_Err_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 )
FT_Stream_Skip(FT_Stream stream,FT_Long distance)92   FT_Stream_Skip( FT_Stream  stream,
93                   FT_Long    distance )
94   {
95     if ( distance < 0 )
96       return FT_Err_Invalid_Stream_Operation;
97 
98     return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) );
99   }
100 
101 
102   FT_BASE_DEF( FT_Long )
FT_Stream_Pos(FT_Stream stream)103   FT_Stream_Pos( FT_Stream  stream )
104   {
105     return stream->pos;
106   }
107 
108 
109   FT_BASE_DEF( FT_Error )
FT_Stream_Read(FT_Stream stream,FT_Byte * buffer,FT_ULong count)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 )
FT_Stream_ReadAt(FT_Stream stream,FT_ULong pos,FT_Byte * buffer,FT_ULong count)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_Err_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_Err_Invalid_Stream_Operation;
157     }
158 
159     return error;
160   }
161 
162 
163   FT_BASE_DEF( FT_ULong )
FT_Stream_TryRead(FT_Stream stream,FT_Byte * buffer,FT_ULong count)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 )
FT_Stream_ExtractFrame(FT_Stream stream,FT_ULong count,FT_Byte ** pbytes)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 )
FT_Stream_ReleaseFrame(FT_Stream stream,FT_Byte ** pbytes)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 )
FT_Stream_EnterFrame(FT_Stream stream,FT_ULong count)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_Err_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_Err_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_Err_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 )
FT_Stream_ExitFrame(FT_Stream stream)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 )
FT_Stream_GetChar(FT_Stream stream)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 )
FT_Stream_GetUShort(FT_Stream stream)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 )
FT_Stream_GetUShortLE(FT_Stream stream)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 )
FT_Stream_GetUOffset(FT_Stream stream)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 )
FT_Stream_GetULong(FT_Stream stream)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 )
FT_Stream_GetULongLE(FT_Stream stream)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 )
FT_Stream_ReadChar(FT_Stream stream,FT_Error * error)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_Err_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 )
FT_Stream_ReadUShort(FT_Stream stream,FT_Error * error)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_Err_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 )
FT_Stream_ReadUShortLE(FT_Stream stream,FT_Error * error)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_Err_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 )
FT_Stream_ReadUOffset(FT_Stream stream,FT_Error * error)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_Err_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 )
FT_Stream_ReadULong(FT_Stream stream,FT_Error * error)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_Err_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 )
FT_Stream_ReadULongLE(FT_Stream stream,FT_Error * error)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_Err_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 )
FT_Stream_ReadFields(FT_Stream stream,const FT_Frame_Field * fields,void * structure)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     if ( !fields || !stream )
731       return FT_Err_Invalid_Argument;
732 
733     cursor = stream->cursor;
734 
735     error = FT_Err_Ok;
736     do
737     {
738       FT_ULong  value;
739       FT_Int    sign_shift;
740       FT_Byte*  p;
741 
742 
743       switch ( fields->value )
744       {
745       case ft_frame_start:  /* access a new frame */
746         error = FT_Stream_EnterFrame( stream, fields->offset );
747         if ( error )
748           goto Exit;
749 
750         frame_accessed = 1;
751         cursor         = stream->cursor;
752         fields++;
753         continue;  /* loop! */
754 
755       case ft_frame_bytes:  /* read a byte sequence */
756       case ft_frame_skip:   /* skip some bytes      */
757         {
758           FT_UInt  len = fields->size;
759 
760 
761           if ( cursor + len > stream->limit )
762           {
763             error = FT_Err_Invalid_Stream_Operation;
764             goto Exit;
765           }
766 
767           if ( fields->value == ft_frame_bytes )
768           {
769             p = (FT_Byte*)structure + fields->offset;
770             FT_MEM_COPY( p, cursor, len );
771           }
772           cursor += len;
773           fields++;
774           continue;
775         }
776 
777       case ft_frame_byte:
778       case ft_frame_schar:  /* read a single byte */
779         value = FT_NEXT_BYTE(cursor);
780         sign_shift = 24;
781         break;
782 
783       case ft_frame_short_be:
784       case ft_frame_ushort_be:  /* read a 2-byte big-endian short */
785         value = FT_NEXT_USHORT(cursor);
786         sign_shift = 16;
787         break;
788 
789       case ft_frame_short_le:
790       case ft_frame_ushort_le:  /* read a 2-byte little-endian short */
791         value = FT_NEXT_USHORT_LE(cursor);
792         sign_shift = 16;
793         break;
794 
795       case ft_frame_long_be:
796       case ft_frame_ulong_be:  /* read a 4-byte big-endian long */
797         value = FT_NEXT_ULONG(cursor);
798         sign_shift = 0;
799         break;
800 
801       case ft_frame_long_le:
802       case ft_frame_ulong_le:  /* read a 4-byte little-endian long */
803         value = FT_NEXT_ULONG_LE(cursor);
804         sign_shift = 0;
805         break;
806 
807       case ft_frame_off3_be:
808       case ft_frame_uoff3_be:  /* read a 3-byte big-endian long */
809         value = FT_NEXT_UOFF3(cursor);
810         sign_shift = 8;
811         break;
812 
813       case ft_frame_off3_le:
814       case ft_frame_uoff3_le:  /* read a 3-byte little-endian long */
815         value = FT_NEXT_UOFF3_LE(cursor);
816         sign_shift = 8;
817         break;
818 
819       default:
820         /* otherwise, exit the loop */
821         stream->cursor = cursor;
822         goto Exit;
823       }
824 
825       /* now, compute the signed value is necessary */
826       if ( fields->value & FT_FRAME_OP_SIGNED )
827         value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
828 
829       /* finally, store the value in the object */
830 
831       p = (FT_Byte*)structure + fields->offset;
832       switch ( fields->size )
833       {
834       case (8 / FT_CHAR_BIT):
835         *(FT_Byte*)p = (FT_Byte)value;
836         break;
837 
838       case (16 / FT_CHAR_BIT):
839         *(FT_UShort*)p = (FT_UShort)value;
840         break;
841 
842       case (32 / FT_CHAR_BIT):
843         *(FT_UInt32*)p = (FT_UInt32)value;
844         break;
845 
846       default:  /* for 64-bit systems */
847         *(FT_ULong*)p = (FT_ULong)value;
848       }
849 
850       /* go to next field */
851       fields++;
852     }
853     while ( 1 );
854 
855   Exit:
856     /* close the frame if it was opened by this read */
857     if ( frame_accessed )
858       FT_Stream_ExitFrame( stream );
859 
860     return error;
861   }
862 
863 
864 /* END */
865