• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ftstream.c
4  *
5  *   I/O stream support (body).
6  *
7  * Copyright 2000-2018 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 = NULL;
43     stream->read   = NULL;
44     stream->close  = NULL;
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_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 )
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_THROW( Invalid_Stream_Operation );
97 
98     return FT_Stream_Seek( stream, stream->pos + (FT_ULong)distance );
99   }
100 
101 
102   FT_BASE_DEF( FT_ULong )
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_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 )
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 = NULL;
207       stream->limit  = NULL;
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 
223 #ifdef FT_DEBUG_MEMORY
224       ft_mem_free( memory, *pbytes );
225       *pbytes = NULL;
226 #else
227       FT_FREE( *pbytes );
228 #endif
229     }
230     *pbytes = NULL;
231   }
232 
233 
234   FT_BASE_DEF( FT_Error )
FT_Stream_EnterFrame(FT_Stream stream,FT_ULong count)235   FT_Stream_EnterFrame( FT_Stream  stream,
236                         FT_ULong   count )
237   {
238     FT_Error  error = FT_Err_Ok;
239     FT_ULong  read_bytes;
240 
241 
242     /* check for nested frame access */
243     FT_ASSERT( stream && stream->cursor == 0 );
244 
245     if ( stream->read )
246     {
247       /* allocate the frame in memory */
248       FT_Memory  memory = stream->memory;
249 
250 
251       /* simple sanity check */
252       if ( count > stream->size )
253       {
254         FT_ERROR(( "FT_Stream_EnterFrame:"
255                    " frame size (%lu) larger than stream size (%lu)\n",
256                    count, stream->size ));
257 
258         error = FT_THROW( Invalid_Stream_Operation );
259         goto Exit;
260       }
261 
262 #ifdef FT_DEBUG_MEMORY
263       /* assume _ft_debug_file and _ft_debug_lineno are already set */
264       stream->base = (unsigned char*)ft_mem_qalloc( memory,
265                                                     (FT_Long)count,
266                                                     &error );
267       if ( error )
268         goto Exit;
269 #else
270       if ( FT_QALLOC( stream->base, count ) )
271         goto Exit;
272 #endif
273       /* read it */
274       read_bytes = stream->read( stream, stream->pos,
275                                  stream->base, count );
276       if ( read_bytes < count )
277       {
278         FT_ERROR(( "FT_Stream_EnterFrame:"
279                    " invalid read; expected %lu bytes, got %lu\n",
280                    count, read_bytes ));
281 
282         FT_FREE( stream->base );
283         error = FT_THROW( Invalid_Stream_Operation );
284       }
285       stream->cursor = stream->base;
286       stream->limit  = stream->cursor + count;
287       stream->pos   += read_bytes;
288     }
289     else
290     {
291       /* check current and new position */
292       if ( stream->pos >= stream->size        ||
293            stream->size - stream->pos < count )
294       {
295         FT_ERROR(( "FT_Stream_EnterFrame:"
296                    " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
297                    stream->pos, count, stream->size ));
298 
299         error = FT_THROW( Invalid_Stream_Operation );
300         goto Exit;
301       }
302 
303       /* set cursor */
304       stream->cursor = stream->base + stream->pos;
305       stream->limit  = stream->cursor + count;
306       stream->pos   += count;
307     }
308 
309   Exit:
310     return error;
311   }
312 
313 
314   FT_BASE_DEF( void )
FT_Stream_ExitFrame(FT_Stream stream)315   FT_Stream_ExitFrame( FT_Stream  stream )
316   {
317     /* IMPORTANT: The assertion stream->cursor != 0 was removed, given    */
318     /*            that it is possible to access a frame of length 0 in    */
319     /*            some weird fonts (usually, when accessing an array of   */
320     /*            0 records, like in some strange kern tables).           */
321     /*                                                                    */
322     /*  In this case, the loader code handles the 0-length table          */
323     /*  gracefully; however, stream.cursor is really set to 0 by the      */
324     /*  FT_Stream_EnterFrame() call, and this is not an error.            */
325     /*                                                                    */
326     FT_ASSERT( stream );
327 
328     if ( stream->read )
329     {
330       FT_Memory  memory = stream->memory;
331 
332 #ifdef FT_DEBUG_MEMORY
333       ft_mem_free( memory, stream->base );
334       stream->base = NULL;
335 #else
336       FT_FREE( stream->base );
337 #endif
338     }
339     stream->cursor = NULL;
340     stream->limit  = NULL;
341   }
342 
343 
344   FT_BASE_DEF( FT_Char )
FT_Stream_GetChar(FT_Stream stream)345   FT_Stream_GetChar( FT_Stream  stream )
346   {
347     FT_Char  result;
348 
349 
350     FT_ASSERT( stream && stream->cursor );
351 
352     result = 0;
353     if ( stream->cursor < stream->limit )
354       result = (FT_Char)*stream->cursor++;
355 
356     return result;
357   }
358 
359 
360   FT_BASE_DEF( FT_UShort )
FT_Stream_GetUShort(FT_Stream stream)361   FT_Stream_GetUShort( FT_Stream  stream )
362   {
363     FT_Byte*   p;
364     FT_UShort  result;
365 
366 
367     FT_ASSERT( stream && stream->cursor );
368 
369     result         = 0;
370     p              = stream->cursor;
371     if ( p + 1 < stream->limit )
372       result       = FT_NEXT_USHORT( p );
373     stream->cursor = p;
374 
375     return result;
376   }
377 
378 
379   FT_BASE_DEF( FT_UShort )
FT_Stream_GetUShortLE(FT_Stream stream)380   FT_Stream_GetUShortLE( FT_Stream  stream )
381   {
382     FT_Byte*   p;
383     FT_UShort  result;
384 
385 
386     FT_ASSERT( stream && stream->cursor );
387 
388     result         = 0;
389     p              = stream->cursor;
390     if ( p + 1 < stream->limit )
391       result       = FT_NEXT_USHORT_LE( p );
392     stream->cursor = p;
393 
394     return result;
395   }
396 
397 
398   FT_BASE_DEF( FT_ULong )
FT_Stream_GetUOffset(FT_Stream stream)399   FT_Stream_GetUOffset( FT_Stream  stream )
400   {
401     FT_Byte*  p;
402     FT_ULong  result;
403 
404 
405     FT_ASSERT( stream && stream->cursor );
406 
407     result         = 0;
408     p              = stream->cursor;
409     if ( p + 2 < stream->limit )
410       result       = FT_NEXT_UOFF3( p );
411     stream->cursor = p;
412     return result;
413   }
414 
415 
416   FT_BASE_DEF( FT_ULong )
FT_Stream_GetULong(FT_Stream stream)417   FT_Stream_GetULong( FT_Stream  stream )
418   {
419     FT_Byte*  p;
420     FT_ULong  result;
421 
422 
423     FT_ASSERT( stream && stream->cursor );
424 
425     result         = 0;
426     p              = stream->cursor;
427     if ( p + 3 < stream->limit )
428       result       = FT_NEXT_ULONG( p );
429     stream->cursor = p;
430     return result;
431   }
432 
433 
434   FT_BASE_DEF( FT_ULong )
FT_Stream_GetULongLE(FT_Stream stream)435   FT_Stream_GetULongLE( FT_Stream  stream )
436   {
437     FT_Byte*  p;
438     FT_ULong  result;
439 
440 
441     FT_ASSERT( stream && stream->cursor );
442 
443     result         = 0;
444     p              = stream->cursor;
445     if ( p + 3 < stream->limit )
446       result       = FT_NEXT_ULONG_LE( p );
447     stream->cursor = p;
448     return result;
449   }
450 
451 
452   FT_BASE_DEF( FT_Char )
FT_Stream_ReadChar(FT_Stream stream,FT_Error * error)453   FT_Stream_ReadChar( FT_Stream  stream,
454                       FT_Error*  error )
455   {
456     FT_Byte  result = 0;
457 
458 
459     FT_ASSERT( stream );
460 
461     *error = FT_Err_Ok;
462 
463     if ( stream->read )
464     {
465       if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
466         goto Fail;
467     }
468     else
469     {
470       if ( stream->pos < stream->size )
471         result = stream->base[stream->pos];
472       else
473         goto Fail;
474     }
475     stream->pos++;
476 
477     return (FT_Char)result;
478 
479   Fail:
480     *error = FT_THROW( Invalid_Stream_Operation );
481     FT_ERROR(( "FT_Stream_ReadChar:"
482                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
483                stream->pos, stream->size ));
484 
485     return 0;
486   }
487 
488 
489   FT_BASE_DEF( FT_UShort )
FT_Stream_ReadUShort(FT_Stream stream,FT_Error * error)490   FT_Stream_ReadUShort( FT_Stream  stream,
491                         FT_Error*  error )
492   {
493     FT_Byte    reads[2];
494     FT_Byte*   p      = 0;
495     FT_UShort  result = 0;
496 
497 
498     FT_ASSERT( stream );
499 
500     *error = FT_Err_Ok;
501 
502     if ( stream->pos + 1 < stream->size )
503     {
504       if ( stream->read )
505       {
506         if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
507           goto Fail;
508 
509         p = reads;
510       }
511       else
512         p = stream->base + stream->pos;
513 
514       if ( p )
515         result = FT_NEXT_USHORT( p );
516     }
517     else
518       goto Fail;
519 
520     stream->pos += 2;
521 
522     return result;
523 
524   Fail:
525     *error = FT_THROW( Invalid_Stream_Operation );
526     FT_ERROR(( "FT_Stream_ReadUShort:"
527                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
528                stream->pos, stream->size ));
529 
530     return 0;
531   }
532 
533 
534   FT_BASE_DEF( FT_UShort )
FT_Stream_ReadUShortLE(FT_Stream stream,FT_Error * error)535   FT_Stream_ReadUShortLE( FT_Stream  stream,
536                           FT_Error*  error )
537   {
538     FT_Byte    reads[2];
539     FT_Byte*   p      = 0;
540     FT_UShort  result = 0;
541 
542 
543     FT_ASSERT( stream );
544 
545     *error = FT_Err_Ok;
546 
547     if ( stream->pos + 1 < stream->size )
548     {
549       if ( stream->read )
550       {
551         if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
552           goto Fail;
553 
554         p = reads;
555       }
556       else
557         p = stream->base + stream->pos;
558 
559       if ( p )
560         result = FT_NEXT_USHORT_LE( p );
561     }
562     else
563       goto Fail;
564 
565     stream->pos += 2;
566 
567     return result;
568 
569   Fail:
570     *error = FT_THROW( Invalid_Stream_Operation );
571     FT_ERROR(( "FT_Stream_ReadUShortLE:"
572                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
573                stream->pos, stream->size ));
574 
575     return 0;
576   }
577 
578 
579   FT_BASE_DEF( FT_ULong )
FT_Stream_ReadUOffset(FT_Stream stream,FT_Error * error)580   FT_Stream_ReadUOffset( FT_Stream  stream,
581                          FT_Error*  error )
582   {
583     FT_Byte   reads[3];
584     FT_Byte*  p      = 0;
585     FT_ULong  result = 0;
586 
587 
588     FT_ASSERT( stream );
589 
590     *error = FT_Err_Ok;
591 
592     if ( stream->pos + 2 < stream->size )
593     {
594       if ( stream->read )
595       {
596         if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
597           goto Fail;
598 
599         p = reads;
600       }
601       else
602         p = stream->base + stream->pos;
603 
604       if ( p )
605         result = FT_NEXT_UOFF3( p );
606     }
607     else
608       goto Fail;
609 
610     stream->pos += 3;
611 
612     return result;
613 
614   Fail:
615     *error = FT_THROW( Invalid_Stream_Operation );
616     FT_ERROR(( "FT_Stream_ReadUOffset:"
617                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
618                stream->pos, stream->size ));
619 
620     return 0;
621   }
622 
623 
624   FT_BASE_DEF( FT_ULong )
FT_Stream_ReadULong(FT_Stream stream,FT_Error * error)625   FT_Stream_ReadULong( FT_Stream  stream,
626                        FT_Error*  error )
627   {
628     FT_Byte   reads[4];
629     FT_Byte*  p      = 0;
630     FT_ULong  result = 0;
631 
632 
633     FT_ASSERT( stream );
634 
635     *error = FT_Err_Ok;
636 
637     if ( stream->pos + 3 < stream->size )
638     {
639       if ( stream->read )
640       {
641         if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
642           goto Fail;
643 
644         p = reads;
645       }
646       else
647         p = stream->base + stream->pos;
648 
649       if ( p )
650         result = FT_NEXT_ULONG( p );
651     }
652     else
653       goto Fail;
654 
655     stream->pos += 4;
656 
657     return result;
658 
659   Fail:
660     *error = FT_THROW( Invalid_Stream_Operation );
661     FT_ERROR(( "FT_Stream_ReadULong:"
662                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
663                stream->pos, stream->size ));
664 
665     return 0;
666   }
667 
668 
669   FT_BASE_DEF( FT_ULong )
FT_Stream_ReadULongLE(FT_Stream stream,FT_Error * error)670   FT_Stream_ReadULongLE( FT_Stream  stream,
671                          FT_Error*  error )
672   {
673     FT_Byte   reads[4];
674     FT_Byte*  p      = 0;
675     FT_ULong  result = 0;
676 
677 
678     FT_ASSERT( stream );
679 
680     *error = FT_Err_Ok;
681 
682     if ( stream->pos + 3 < stream->size )
683     {
684       if ( stream->read )
685       {
686         if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
687           goto Fail;
688 
689         p = reads;
690       }
691       else
692         p = stream->base + stream->pos;
693 
694       if ( p )
695         result = FT_NEXT_ULONG_LE( p );
696     }
697     else
698       goto Fail;
699 
700     stream->pos += 4;
701 
702     return result;
703 
704   Fail:
705     *error = FT_THROW( Invalid_Stream_Operation );
706     FT_ERROR(( "FT_Stream_ReadULongLE:"
707                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
708                stream->pos, stream->size ));
709 
710     return 0;
711   }
712 
713 
714   FT_BASE_DEF( FT_Error )
FT_Stream_ReadFields(FT_Stream stream,const FT_Frame_Field * fields,void * structure)715   FT_Stream_ReadFields( FT_Stream              stream,
716                         const FT_Frame_Field*  fields,
717                         void*                  structure )
718   {
719     FT_Error  error;
720     FT_Bool   frame_accessed = 0;
721     FT_Byte*  cursor;
722 
723 
724     if ( !fields )
725       return FT_THROW( Invalid_Argument );
726 
727     if ( !stream )
728       return FT_THROW( Invalid_Stream_Handle );
729 
730     cursor = stream->cursor;
731 
732     error = FT_Err_Ok;
733     do
734     {
735       FT_ULong  value;
736       FT_Int    sign_shift;
737       FT_Byte*  p;
738 
739 
740       switch ( fields->value )
741       {
742       case ft_frame_start:  /* access a new frame */
743         error = FT_Stream_EnterFrame( stream, fields->offset );
744         if ( error )
745           goto Exit;
746 
747         frame_accessed = 1;
748         cursor         = stream->cursor;
749         fields++;
750         continue;  /* loop! */
751 
752       case ft_frame_bytes:  /* read a byte sequence */
753       case ft_frame_skip:   /* skip some bytes      */
754         {
755           FT_UInt  len = fields->size;
756 
757 
758           if ( cursor + len > stream->limit )
759           {
760             error = FT_THROW( Invalid_Stream_Operation );
761             goto Exit;
762           }
763 
764           if ( fields->value == ft_frame_bytes )
765           {
766             p = (FT_Byte*)structure + fields->offset;
767             FT_MEM_COPY( p, cursor, len );
768           }
769           cursor += len;
770           fields++;
771           continue;
772         }
773 
774       case ft_frame_byte:
775       case ft_frame_schar:  /* read a single byte */
776         value = FT_NEXT_BYTE( cursor );
777         sign_shift = 24;
778         break;
779 
780       case ft_frame_short_be:
781       case ft_frame_ushort_be:  /* read a 2-byte big-endian short */
782         value = FT_NEXT_USHORT( cursor );
783         sign_shift = 16;
784         break;
785 
786       case ft_frame_short_le:
787       case ft_frame_ushort_le:  /* read a 2-byte little-endian short */
788         value = FT_NEXT_USHORT_LE( cursor );
789         sign_shift = 16;
790         break;
791 
792       case ft_frame_long_be:
793       case ft_frame_ulong_be:  /* read a 4-byte big-endian long */
794         value = FT_NEXT_ULONG( cursor );
795         sign_shift = 0;
796         break;
797 
798       case ft_frame_long_le:
799       case ft_frame_ulong_le:  /* read a 4-byte little-endian long */
800         value = FT_NEXT_ULONG_LE( cursor );
801         sign_shift = 0;
802         break;
803 
804       case ft_frame_off3_be:
805       case ft_frame_uoff3_be:  /* read a 3-byte big-endian long */
806         value = FT_NEXT_UOFF3( cursor );
807         sign_shift = 8;
808         break;
809 
810       case ft_frame_off3_le:
811       case ft_frame_uoff3_le:  /* read a 3-byte little-endian long */
812         value = FT_NEXT_UOFF3_LE( cursor );
813         sign_shift = 8;
814         break;
815 
816       default:
817         /* otherwise, exit the loop */
818         stream->cursor = cursor;
819         goto Exit;
820       }
821 
822       /* now, compute the signed value is necessary */
823       if ( fields->value & FT_FRAME_OP_SIGNED )
824         value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
825 
826       /* finally, store the value in the object */
827 
828       p = (FT_Byte*)structure + fields->offset;
829       switch ( fields->size )
830       {
831       case ( 8 / FT_CHAR_BIT ):
832         *(FT_Byte*)p = (FT_Byte)value;
833         break;
834 
835       case ( 16 / FT_CHAR_BIT ):
836         *(FT_UShort*)p = (FT_UShort)value;
837         break;
838 
839       case ( 32 / FT_CHAR_BIT ):
840         *(FT_UInt32*)p = (FT_UInt32)value;
841         break;
842 
843       default:  /* for 64-bit systems */
844         *(FT_ULong*)p = (FT_ULong)value;
845       }
846 
847       /* go to next field */
848       fields++;
849     }
850     while ( 1 );
851 
852   Exit:
853     /* close the frame if it was opened by this read */
854     if ( frame_accessed )
855       FT_Stream_ExitFrame( stream );
856 
857     return error;
858   }
859 
860 
861 /* END */
862