misc/libfreetype/src/base/ftstream.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ftstream.c                                                             */
       
     4 /*                                                                         */
       
     5 /*    I/O stream support (body).                                           */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2000-2002, 2004-2006, 2008-2011 by                           */
       
     8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
       
     9 /*                                                                         */
       
    10 /*  This file is part of the FreeType project, and may only be used,       */
       
    11 /*  modified, and distributed under the terms of the FreeType project      */
       
    12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
       
    13 /*  this file you indicate that you have read the license and              */
       
    14 /*  understand and accept it fully.                                        */
       
    15 /*                                                                         */
       
    16 /***************************************************************************/
       
    17 
       
    18 
       
    19 #include <ft2build.h>
       
    20 #include FT_INTERNAL_STREAM_H
       
    21 #include FT_INTERNAL_DEBUG_H
       
    22 
       
    23 
       
    24   /*************************************************************************/
       
    25   /*                                                                       */
       
    26   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
       
    27   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
       
    28   /* messages during execution.                                            */
       
    29   /*                                                                       */
       
    30 #undef  FT_COMPONENT
       
    31 #define FT_COMPONENT  trace_stream
       
    32 
       
    33 
       
    34   FT_BASE_DEF( void )
       
    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_Err_Invalid_Stream_Operation;
       
    72       }
       
    73     }
       
    74     /* note that seeking to the first position after the file is valid */
       
    75     else if ( pos > stream->size )
       
    76     {
       
    77       FT_ERROR(( "FT_Stream_Seek:"
       
    78                  " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
       
    79                  pos, stream->size ));
       
    80 
       
    81       error = FT_Err_Invalid_Stream_Operation;
       
    82     }
       
    83 
       
    84     if ( !error )
       
    85       stream->pos = pos;
       
    86 
       
    87     return error;
       
    88   }
       
    89 
       
    90 
       
    91   FT_BASE_DEF( FT_Error )
       
    92   FT_Stream_Skip( FT_Stream  stream,
       
    93                   FT_Long    distance )
       
    94   {
       
    95     if ( distance < 0 )
       
    96       return FT_Err_Invalid_Stream_Operation;
       
    97 
       
    98     return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) );
       
    99   }
       
   100 
       
   101 
       
   102   FT_BASE_DEF( FT_Long )
       
   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_Err_Invalid_Stream_Operation;
       
   135     }
       
   136 
       
   137     if ( stream->read )
       
   138       read_bytes = stream->read( stream, pos, buffer, count );
       
   139     else
       
   140     {
       
   141       read_bytes = stream->size - pos;
       
   142       if ( read_bytes > count )
       
   143         read_bytes = count;
       
   144 
       
   145       FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
       
   146     }
       
   147 
       
   148     stream->pos = pos + read_bytes;
       
   149 
       
   150     if ( read_bytes < count )
       
   151     {
       
   152       FT_ERROR(( "FT_Stream_ReadAt:"
       
   153                  " invalid read; expected %lu bytes, got %lu\n",
       
   154                  count, read_bytes ));
       
   155 
       
   156       error = FT_Err_Invalid_Stream_Operation;
       
   157     }
       
   158 
       
   159     return error;
       
   160   }
       
   161 
       
   162 
       
   163   FT_BASE_DEF( FT_ULong )
       
   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_Err_Invalid_Stream_Operation;
       
   258         goto Exit;
       
   259       }
       
   260 
       
   261 #ifdef FT_DEBUG_MEMORY
       
   262       /* assume _ft_debug_file and _ft_debug_lineno are already set */
       
   263       stream->base = (unsigned char*)ft_mem_qalloc( memory, count, &error );
       
   264       if ( error )
       
   265         goto Exit;
       
   266 #else
       
   267       if ( FT_QALLOC( stream->base, count ) )
       
   268         goto Exit;
       
   269 #endif
       
   270       /* read it */
       
   271       read_bytes = stream->read( stream, stream->pos,
       
   272                                  stream->base, count );
       
   273       if ( read_bytes < count )
       
   274       {
       
   275         FT_ERROR(( "FT_Stream_EnterFrame:"
       
   276                    " invalid read; expected %lu bytes, got %lu\n",
       
   277                    count, read_bytes ));
       
   278 
       
   279         FT_FREE( stream->base );
       
   280         error = FT_Err_Invalid_Stream_Operation;
       
   281       }
       
   282       stream->cursor = stream->base;
       
   283       stream->limit  = stream->cursor + count;
       
   284       stream->pos   += read_bytes;
       
   285     }
       
   286     else
       
   287     {
       
   288       /* check current and new position */
       
   289       if ( stream->pos >= stream->size        ||
       
   290            stream->size - stream->pos < count )
       
   291       {
       
   292         FT_ERROR(( "FT_Stream_EnterFrame:"
       
   293                    " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
       
   294                    stream->pos, count, stream->size ));
       
   295 
       
   296         error = FT_Err_Invalid_Stream_Operation;
       
   297         goto Exit;
       
   298       }
       
   299 
       
   300       /* set cursor */
       
   301       stream->cursor = stream->base + stream->pos;
       
   302       stream->limit  = stream->cursor + count;
       
   303       stream->pos   += count;
       
   304     }
       
   305 
       
   306   Exit:
       
   307     return error;
       
   308   }
       
   309 
       
   310 
       
   311   FT_BASE_DEF( void )
       
   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_Err_Invalid_Stream_Operation;
       
   478     FT_ERROR(( "FT_Stream_ReadChar:"
       
   479                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
       
   480                stream->pos, stream->size ));
       
   481 
       
   482     return 0;
       
   483   }
       
   484 
       
   485 
       
   486   FT_BASE_DEF( FT_UShort )
       
   487   FT_Stream_ReadUShort( FT_Stream  stream,
       
   488                        FT_Error*  error )
       
   489   {
       
   490     FT_Byte   reads[2];
       
   491     FT_Byte*  p = 0;
       
   492     FT_Short  result = 0;
       
   493 
       
   494 
       
   495     FT_ASSERT( stream );
       
   496 
       
   497     *error = FT_Err_Ok;
       
   498 
       
   499     if ( stream->pos + 1 < stream->size )
       
   500     {
       
   501       if ( stream->read )
       
   502       {
       
   503         if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
       
   504           goto Fail;
       
   505 
       
   506         p = reads;
       
   507       }
       
   508       else
       
   509       {
       
   510         p = stream->base + stream->pos;
       
   511       }
       
   512 
       
   513       if ( p )
       
   514         result = FT_NEXT_USHORT( p );
       
   515     }
       
   516     else
       
   517       goto Fail;
       
   518 
       
   519     stream->pos += 2;
       
   520 
       
   521     return result;
       
   522 
       
   523   Fail:
       
   524     *error = FT_Err_Invalid_Stream_Operation;
       
   525     FT_ERROR(( "FT_Stream_ReadUShort:"
       
   526                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
       
   527                stream->pos, stream->size ));
       
   528 
       
   529     return 0;
       
   530   }
       
   531 
       
   532 
       
   533   FT_BASE_DEF( FT_UShort )
       
   534   FT_Stream_ReadUShortLE( FT_Stream  stream,
       
   535                          FT_Error*  error )
       
   536   {
       
   537     FT_Byte   reads[2];
       
   538     FT_Byte*  p = 0;
       
   539     FT_Short  result = 0;
       
   540 
       
   541 
       
   542     FT_ASSERT( stream );
       
   543 
       
   544     *error = FT_Err_Ok;
       
   545 
       
   546     if ( stream->pos + 1 < stream->size )
       
   547     {
       
   548       if ( stream->read )
       
   549       {
       
   550         if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
       
   551           goto Fail;
       
   552 
       
   553         p = reads;
       
   554       }
       
   555       else
       
   556       {
       
   557         p = stream->base + stream->pos;
       
   558       }
       
   559 
       
   560       if ( p )
       
   561         result = FT_NEXT_USHORT_LE( p );
       
   562     }
       
   563     else
       
   564       goto Fail;
       
   565 
       
   566     stream->pos += 2;
       
   567 
       
   568     return result;
       
   569 
       
   570   Fail:
       
   571     *error = FT_Err_Invalid_Stream_Operation;
       
   572     FT_ERROR(( "FT_Stream_ReadUShortLE:"
       
   573                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
       
   574                stream->pos, stream->size ));
       
   575 
       
   576     return 0;
       
   577   }
       
   578 
       
   579 
       
   580   FT_BASE_DEF( FT_ULong )
       
   581   FT_Stream_ReadUOffset( FT_Stream  stream,
       
   582                         FT_Error*  error )
       
   583   {
       
   584     FT_Byte   reads[3];
       
   585     FT_Byte*  p = 0;
       
   586     FT_Long   result = 0;
       
   587 
       
   588 
       
   589     FT_ASSERT( stream );
       
   590 
       
   591     *error = FT_Err_Ok;
       
   592 
       
   593     if ( stream->pos + 2 < stream->size )
       
   594     {
       
   595       if ( stream->read )
       
   596       {
       
   597         if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
       
   598           goto Fail;
       
   599 
       
   600         p = reads;
       
   601       }
       
   602       else
       
   603       {
       
   604         p = stream->base + stream->pos;
       
   605       }
       
   606 
       
   607       if ( p )
       
   608         result = FT_NEXT_UOFF3( p );
       
   609     }
       
   610     else
       
   611       goto Fail;
       
   612 
       
   613     stream->pos += 3;
       
   614 
       
   615     return result;
       
   616 
       
   617   Fail:
       
   618     *error = FT_Err_Invalid_Stream_Operation;
       
   619     FT_ERROR(( "FT_Stream_ReadUOffset:"
       
   620                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
       
   621                stream->pos, stream->size ));
       
   622 
       
   623     return 0;
       
   624   }
       
   625 
       
   626 
       
   627   FT_BASE_DEF( FT_ULong )
       
   628   FT_Stream_ReadULong( FT_Stream  stream,
       
   629                       FT_Error*  error )
       
   630   {
       
   631     FT_Byte   reads[4];
       
   632     FT_Byte*  p = 0;
       
   633     FT_Long   result = 0;
       
   634 
       
   635 
       
   636     FT_ASSERT( stream );
       
   637 
       
   638     *error = FT_Err_Ok;
       
   639 
       
   640     if ( stream->pos + 3 < stream->size )
       
   641     {
       
   642       if ( stream->read )
       
   643       {
       
   644         if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
       
   645           goto Fail;
       
   646 
       
   647         p = reads;
       
   648       }
       
   649       else
       
   650       {
       
   651         p = stream->base + stream->pos;
       
   652       }
       
   653 
       
   654       if ( p )
       
   655         result = FT_NEXT_ULONG( p );
       
   656     }
       
   657     else
       
   658       goto Fail;
       
   659 
       
   660     stream->pos += 4;
       
   661 
       
   662     return result;
       
   663 
       
   664   Fail:
       
   665     *error = FT_Err_Invalid_Stream_Operation;
       
   666     FT_ERROR(( "FT_Stream_ReadULong:"
       
   667                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
       
   668                stream->pos, stream->size ));
       
   669 
       
   670     return 0;
       
   671   }
       
   672 
       
   673 
       
   674   FT_BASE_DEF( FT_ULong )
       
   675   FT_Stream_ReadULongLE( FT_Stream  stream,
       
   676                         FT_Error*  error )
       
   677   {
       
   678     FT_Byte   reads[4];
       
   679     FT_Byte*  p = 0;
       
   680     FT_Long   result = 0;
       
   681 
       
   682 
       
   683     FT_ASSERT( stream );
       
   684 
       
   685     *error = FT_Err_Ok;
       
   686 
       
   687     if ( stream->pos + 3 < stream->size )
       
   688     {
       
   689       if ( stream->read )
       
   690       {
       
   691         if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
       
   692           goto Fail;
       
   693 
       
   694         p = reads;
       
   695       }
       
   696       else
       
   697       {
       
   698         p = stream->base + stream->pos;
       
   699       }
       
   700 
       
   701       if ( p )
       
   702         result = FT_NEXT_ULONG_LE( p );
       
   703     }
       
   704     else
       
   705       goto Fail;
       
   706 
       
   707     stream->pos += 4;
       
   708 
       
   709     return result;
       
   710 
       
   711   Fail:
       
   712     *error = FT_Err_Invalid_Stream_Operation;
       
   713     FT_ERROR(( "FT_Stream_ReadULongLE:"
       
   714                " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
       
   715                stream->pos, stream->size ));
       
   716 
       
   717     return 0;
       
   718   }
       
   719 
       
   720 
       
   721   FT_BASE_DEF( FT_Error )
       
   722   FT_Stream_ReadFields( FT_Stream              stream,
       
   723                         const FT_Frame_Field*  fields,
       
   724                         void*                  structure )
       
   725   {
       
   726     FT_Error  error;
       
   727     FT_Bool   frame_accessed = 0;
       
   728     FT_Byte*  cursor;
       
   729 
       
   730     if ( !fields || !stream )
       
   731       return FT_Err_Invalid_Argument;
       
   732 
       
   733     cursor = stream->cursor;
       
   734 
       
   735     error = FT_Err_Ok;
       
   736     do
       
   737     {
       
   738       FT_ULong  value;
       
   739       FT_Int    sign_shift;
       
   740       FT_Byte*  p;
       
   741 
       
   742 
       
   743       switch ( fields->value )
       
   744       {
       
   745       case ft_frame_start:  /* access a new frame */
       
   746         error = FT_Stream_EnterFrame( stream, fields->offset );
       
   747         if ( error )
       
   748           goto Exit;
       
   749 
       
   750         frame_accessed = 1;
       
   751         cursor         = stream->cursor;
       
   752         fields++;
       
   753         continue;  /* loop! */
       
   754 
       
   755       case ft_frame_bytes:  /* read a byte sequence */
       
   756       case ft_frame_skip:   /* skip some bytes      */
       
   757         {
       
   758           FT_UInt  len = fields->size;
       
   759 
       
   760 
       
   761           if ( cursor + len > stream->limit )
       
   762           {
       
   763             error = FT_Err_Invalid_Stream_Operation;
       
   764             goto Exit;
       
   765           }
       
   766 
       
   767           if ( fields->value == ft_frame_bytes )
       
   768           {
       
   769             p = (FT_Byte*)structure + fields->offset;
       
   770             FT_MEM_COPY( p, cursor, len );
       
   771           }
       
   772           cursor += len;
       
   773           fields++;
       
   774           continue;
       
   775         }
       
   776 
       
   777       case ft_frame_byte:
       
   778       case ft_frame_schar:  /* read a single byte */
       
   779         value = FT_NEXT_BYTE(cursor);
       
   780         sign_shift = 24;
       
   781         break;
       
   782 
       
   783       case ft_frame_short_be:
       
   784       case ft_frame_ushort_be:  /* read a 2-byte big-endian short */
       
   785         value = FT_NEXT_USHORT(cursor);
       
   786         sign_shift = 16;
       
   787         break;
       
   788 
       
   789       case ft_frame_short_le:
       
   790       case ft_frame_ushort_le:  /* read a 2-byte little-endian short */
       
   791         value = FT_NEXT_USHORT_LE(cursor);
       
   792         sign_shift = 16;
       
   793         break;
       
   794 
       
   795       case ft_frame_long_be:
       
   796       case ft_frame_ulong_be:  /* read a 4-byte big-endian long */
       
   797         value = FT_NEXT_ULONG(cursor);
       
   798         sign_shift = 0;
       
   799         break;
       
   800 
       
   801       case ft_frame_long_le:
       
   802       case ft_frame_ulong_le:  /* read a 4-byte little-endian long */
       
   803         value = FT_NEXT_ULONG_LE(cursor);
       
   804         sign_shift = 0;
       
   805         break;
       
   806 
       
   807       case ft_frame_off3_be:
       
   808       case ft_frame_uoff3_be:  /* read a 3-byte big-endian long */
       
   809         value = FT_NEXT_UOFF3(cursor);
       
   810         sign_shift = 8;
       
   811         break;
       
   812 
       
   813       case ft_frame_off3_le:
       
   814       case ft_frame_uoff3_le:  /* read a 3-byte little-endian long */
       
   815         value = FT_NEXT_UOFF3_LE(cursor);
       
   816         sign_shift = 8;
       
   817         break;
       
   818 
       
   819       default:
       
   820         /* otherwise, exit the loop */
       
   821         stream->cursor = cursor;
       
   822         goto Exit;
       
   823       }
       
   824 
       
   825       /* now, compute the signed value is necessary */
       
   826       if ( fields->value & FT_FRAME_OP_SIGNED )
       
   827         value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
       
   828 
       
   829       /* finally, store the value in the object */
       
   830 
       
   831       p = (FT_Byte*)structure + fields->offset;
       
   832       switch ( fields->size )
       
   833       {
       
   834       case (8 / FT_CHAR_BIT):
       
   835         *(FT_Byte*)p = (FT_Byte)value;
       
   836         break;
       
   837 
       
   838       case (16 / FT_CHAR_BIT):
       
   839         *(FT_UShort*)p = (FT_UShort)value;
       
   840         break;
       
   841 
       
   842       case (32 / FT_CHAR_BIT):
       
   843         *(FT_UInt32*)p = (FT_UInt32)value;
       
   844         break;
       
   845 
       
   846       default:  /* for 64-bit systems */
       
   847         *(FT_ULong*)p = (FT_ULong)value;
       
   848       }
       
   849 
       
   850       /* go to next field */
       
   851       fields++;
       
   852     }
       
   853     while ( 1 );
       
   854 
       
   855   Exit:
       
   856     /* close the frame if it was opened by this read */
       
   857     if ( frame_accessed )
       
   858       FT_Stream_ExitFrame( stream );
       
   859 
       
   860     return error;
       
   861   }
       
   862 
       
   863 
       
   864 /* END */