Home | History | Annotate | Download | only in base
      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 )
     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 )
     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, stream->pos + (FT_ULong)distance );
     99   }
    100 
    101 
    102   FT_BASE_DEF( FT_ULong )
    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 = NULL;
    207       stream->limit  = NULL;
    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 
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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 )
    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