Subversion Repositories Kolibri OS

Rev

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

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