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