summaryrefslogtreecommitdiff
path: root/third_party/freetype/src/base/ftstream.c
diff options
context:
space:
mode:
authorBo Xu <bo_xu@foxitsoftware.com>2014-12-19 14:29:17 -0800
committerBo Xu <bo_xu@foxitsoftware.com>2014-12-19 15:03:12 -0800
commit4c764f391a4cfb82c81117cf9f249a8598be1cc5 (patch)
tree7d0cc6e2db4182a12ecab5f528c9bfccb4b7df6e /third_party/freetype/src/base/ftstream.c
parentd44e39279b08c0954f07283b4fb3e7f3e292e4de (diff)
downloadpdfium-4c764f391a4cfb82c81117cf9f249a8598be1cc5.tar.xz
XFA: merge patch from CL 815103002
Update freetype to 2.5.4. Put freetype into third_party directory, cleaning up header files. Previously freetype header files are in core/src/fxge/freetype and core/include/thirdparties. There were also multiple fx_freetype.h. This patch removes the additional Foxit wrapper to make further update easier. Notice, for original freetype source code, the following files are modified and need to be updated accordingly in future update: third_party/freetype/include/config/ftmodule.h third_party/freetype/include/config/ftoption.h BUG=407341 R=thestig@chromium.org Review URL: https://codereview.chromium.org/815103002
Diffstat (limited to 'third_party/freetype/src/base/ftstream.c')
-rw-r--r--third_party/freetype/src/base/ftstream.c868
1 files changed, 868 insertions, 0 deletions
diff --git a/third_party/freetype/src/base/ftstream.c b/third_party/freetype/src/base/ftstream.c
new file mode 100644
index 0000000000..759fd8fc07
--- /dev/null
+++ b/third_party/freetype/src/base/ftstream.c
@@ -0,0 +1,868 @@
+/***************************************************************************/
+/* */
+/* ftstream.c */
+/* */
+/* I/O stream support (body). */
+/* */
+/* Copyright 2000-2002, 2004-2006, 2008-2011, 2013 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_stream
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_OpenMemory( FT_Stream stream,
+ const FT_Byte* base,
+ FT_ULong size )
+ {
+ stream->base = (FT_Byte*) base;
+ stream->size = size;
+ stream->pos = 0;
+ stream->cursor = 0;
+ stream->read = 0;
+ stream->close = 0;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_Close( FT_Stream stream )
+ {
+ if ( stream && stream->close )
+ stream->close( stream );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_Seek( FT_Stream stream,
+ FT_ULong pos )
+ {
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( stream->read )
+ {
+ if ( stream->read( stream, pos, 0, 0 ) )
+ {
+ FT_ERROR(( "FT_Stream_Seek:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ error = FT_THROW( Invalid_Stream_Operation );
+ }
+ }
+ /* note that seeking to the first position after the file is valid */
+ else if ( pos > stream->size )
+ {
+ FT_ERROR(( "FT_Stream_Seek:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ error = FT_THROW( Invalid_Stream_Operation );
+ }
+
+ if ( !error )
+ stream->pos = pos;
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_Skip( FT_Stream stream,
+ FT_Long distance )
+ {
+ if ( distance < 0 )
+ return FT_THROW( Invalid_Stream_Operation );
+
+ return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) );
+ }
+
+
+ FT_BASE_DEF( FT_Long )
+ FT_Stream_Pos( FT_Stream stream )
+ {
+ return stream->pos;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_Read( FT_Stream stream,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ return FT_Stream_ReadAt( stream, stream->pos, buffer, count );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_ReadAt( FT_Stream stream,
+ FT_ULong pos,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_ULong read_bytes;
+
+
+ if ( pos >= stream->size )
+ {
+ FT_ERROR(( "FT_Stream_ReadAt:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ pos, stream->size ));
+
+ return FT_THROW( Invalid_Stream_Operation );
+ }
+
+ if ( stream->read )
+ read_bytes = stream->read( stream, pos, buffer, count );
+ else
+ {
+ read_bytes = stream->size - pos;
+ if ( read_bytes > count )
+ read_bytes = count;
+
+ FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
+ }
+
+ stream->pos = pos + read_bytes;
+
+ if ( read_bytes < count )
+ {
+ FT_ERROR(( "FT_Stream_ReadAt:"
+ " invalid read; expected %lu bytes, got %lu\n",
+ count, read_bytes ));
+
+ error = FT_THROW( Invalid_Stream_Operation );
+ }
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_TryRead( FT_Stream stream,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ FT_ULong read_bytes = 0;
+
+
+ if ( stream->pos >= stream->size )
+ goto Exit;
+
+ if ( stream->read )
+ read_bytes = stream->read( stream, stream->pos, buffer, count );
+ else
+ {
+ read_bytes = stream->size - stream->pos;
+ if ( read_bytes > count )
+ read_bytes = count;
+
+ FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
+ }
+
+ stream->pos += read_bytes;
+
+ Exit:
+ return read_bytes;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_ExtractFrame( FT_Stream stream,
+ FT_ULong count,
+ FT_Byte** pbytes )
+ {
+ FT_Error error;
+
+
+ error = FT_Stream_EnterFrame( stream, count );
+ if ( !error )
+ {
+ *pbytes = (FT_Byte*)stream->cursor;
+
+ /* equivalent to FT_Stream_ExitFrame(), with no memory block release */
+ stream->cursor = 0;
+ stream->limit = 0;
+ }
+
+ return error;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_ReleaseFrame( FT_Stream stream,
+ FT_Byte** pbytes )
+ {
+ if ( stream && stream->read )
+ {
+ FT_Memory memory = stream->memory;
+
+#ifdef FT_DEBUG_MEMORY
+ ft_mem_free( memory, *pbytes );
+ *pbytes = NULL;
+#else
+ FT_FREE( *pbytes );
+#endif
+ }
+ *pbytes = 0;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_EnterFrame( FT_Stream stream,
+ FT_ULong count )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_ULong read_bytes;
+
+
+ /* check for nested frame access */
+ FT_ASSERT( stream && stream->cursor == 0 );
+
+ if ( stream->read )
+ {
+ /* allocate the frame in memory */
+ FT_Memory memory = stream->memory;
+
+
+ /* simple sanity check */
+ if ( count > stream->size )
+ {
+ FT_ERROR(( "FT_Stream_EnterFrame:"
+ " frame size (%lu) larger than stream size (%lu)\n",
+ count, stream->size ));
+
+ error = FT_THROW( Invalid_Stream_Operation );
+ goto Exit;
+ }
+
+#ifdef FT_DEBUG_MEMORY
+ /* assume _ft_debug_file and _ft_debug_lineno are already set */
+ stream->base = (unsigned char*)ft_mem_qalloc( memory, count, &error );
+ if ( error )
+ goto Exit;
+#else
+ if ( FT_QALLOC( stream->base, count ) )
+ goto Exit;
+#endif
+ /* read it */
+ read_bytes = stream->read( stream, stream->pos,
+ stream->base, count );
+ if ( read_bytes < count )
+ {
+ FT_ERROR(( "FT_Stream_EnterFrame:"
+ " invalid read; expected %lu bytes, got %lu\n",
+ count, read_bytes ));
+
+ FT_FREE( stream->base );
+ error = FT_THROW( Invalid_Stream_Operation );
+ }
+ stream->cursor = stream->base;
+ stream->limit = stream->cursor + count;
+ stream->pos += read_bytes;
+ }
+ else
+ {
+ /* check current and new position */
+ if ( stream->pos >= stream->size ||
+ stream->size - stream->pos < count )
+ {
+ FT_ERROR(( "FT_Stream_EnterFrame:"
+ " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
+ stream->pos, count, stream->size ));
+
+ error = FT_THROW( Invalid_Stream_Operation );
+ goto Exit;
+ }
+
+ /* set cursor */
+ stream->cursor = stream->base + stream->pos;
+ stream->limit = stream->cursor + count;
+ stream->pos += count;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Stream_ExitFrame( FT_Stream stream )
+ {
+ /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */
+ /* that it is possible to access a frame of length 0 in */
+ /* some weird fonts (usually, when accessing an array of */
+ /* 0 records, like in some strange kern tables). */
+ /* */
+ /* In this case, the loader code handles the 0-length table */
+ /* gracefully; however, stream.cursor is really set to 0 by the */
+ /* FT_Stream_EnterFrame() call, and this is not an error. */
+ /* */
+ FT_ASSERT( stream );
+
+ if ( stream->read )
+ {
+ FT_Memory memory = stream->memory;
+
+#ifdef FT_DEBUG_MEMORY
+ ft_mem_free( memory, stream->base );
+ stream->base = NULL;
+#else
+ FT_FREE( stream->base );
+#endif
+ }
+ stream->cursor = 0;
+ stream->limit = 0;
+ }
+
+
+ FT_BASE_DEF( FT_Char )
+ FT_Stream_GetChar( FT_Stream stream )
+ {
+ FT_Char result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ if ( stream->cursor < stream->limit )
+ result = *stream->cursor++;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_UShort )
+ FT_Stream_GetUShort( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Short result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 1 < stream->limit )
+ result = FT_NEXT_USHORT( p );
+ stream->cursor = p;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_UShort )
+ FT_Stream_GetUShortLE( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Short result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 1 < stream->limit )
+ result = FT_NEXT_USHORT_LE( p );
+ stream->cursor = p;
+
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_GetUOffset( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 2 < stream->limit )
+ result = FT_NEXT_UOFF3( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_GetULong( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 3 < stream->limit )
+ result = FT_NEXT_ULONG( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_GetULongLE( FT_Stream stream )
+ {
+ FT_Byte* p;
+ FT_Long result;
+
+
+ FT_ASSERT( stream && stream->cursor );
+
+ result = 0;
+ p = stream->cursor;
+ if ( p + 3 < stream->limit )
+ result = FT_NEXT_ULONG_LE( p );
+ stream->cursor = p;
+ return result;
+ }
+
+
+ FT_BASE_DEF( FT_Char )
+ FT_Stream_ReadChar( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
+ goto Fail;
+ }
+ else
+ {
+ if ( stream->pos < stream->size )
+ result = stream->base[stream->pos];
+ else
+ goto Fail;
+ }
+ stream->pos++;
+
+ return result;
+
+ Fail:
+ *error = FT_THROW( Invalid_Stream_Operation );
+ FT_ERROR(( "FT_Stream_ReadChar:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_UShort )
+ FT_Stream_ReadUShort( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[2];
+ FT_Byte* p = 0;
+ FT_Short result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 1 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_USHORT( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 2;
+
+ return result;
+
+ Fail:
+ *error = FT_THROW( Invalid_Stream_Operation );
+ FT_ERROR(( "FT_Stream_ReadUShort:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_UShort )
+ FT_Stream_ReadUShortLE( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[2];
+ FT_Byte* p = 0;
+ FT_Short result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 1 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_USHORT_LE( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 2;
+
+ return result;
+
+ Fail:
+ *error = FT_THROW( Invalid_Stream_Operation );
+ FT_ERROR(( "FT_Stream_ReadUShortLE:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_ReadUOffset( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[3];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 2 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_UOFF3( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 3;
+
+ return result;
+
+ Fail:
+ *error = FT_THROW( Invalid_Stream_Operation );
+ FT_ERROR(( "FT_Stream_ReadUOffset:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_ReadULong( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[4];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 3 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_ULONG( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 4;
+
+ return result;
+
+ Fail:
+ *error = FT_THROW( Invalid_Stream_Operation );
+ FT_ERROR(( "FT_Stream_ReadULong:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_ULong )
+ FT_Stream_ReadULongLE( FT_Stream stream,
+ FT_Error* error )
+ {
+ FT_Byte reads[4];
+ FT_Byte* p = 0;
+ FT_Long result = 0;
+
+
+ FT_ASSERT( stream );
+
+ *error = FT_Err_Ok;
+
+ if ( stream->pos + 3 < stream->size )
+ {
+ if ( stream->read )
+ {
+ if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
+ goto Fail;
+
+ p = reads;
+ }
+ else
+ {
+ p = stream->base + stream->pos;
+ }
+
+ if ( p )
+ result = FT_NEXT_ULONG_LE( p );
+ }
+ else
+ goto Fail;
+
+ stream->pos += 4;
+
+ return result;
+
+ Fail:
+ *error = FT_THROW( Invalid_Stream_Operation );
+ FT_ERROR(( "FT_Stream_ReadULongLE:"
+ " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+ stream->pos, stream->size ));
+
+ return 0;
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Stream_ReadFields( FT_Stream stream,
+ const FT_Frame_Field* fields,
+ void* structure )
+ {
+ FT_Error error;
+ FT_Bool frame_accessed = 0;
+ FT_Byte* cursor;
+
+
+ if ( !fields )
+ return FT_THROW( Invalid_Argument );
+
+ if ( !stream )
+ return FT_THROW( Invalid_Stream_Handle );
+
+ cursor = stream->cursor;
+
+ error = FT_Err_Ok;
+ do
+ {
+ FT_ULong value;
+ FT_Int sign_shift;
+ FT_Byte* p;
+
+
+ switch ( fields->value )
+ {
+ case ft_frame_start: /* access a new frame */
+ error = FT_Stream_EnterFrame( stream, fields->offset );
+ if ( error )
+ goto Exit;
+
+ frame_accessed = 1;
+ cursor = stream->cursor;
+ fields++;
+ continue; /* loop! */
+
+ case ft_frame_bytes: /* read a byte sequence */
+ case ft_frame_skip: /* skip some bytes */
+ {
+ FT_UInt len = fields->size;
+
+
+ if ( cursor + len > stream->limit )
+ {
+ error = FT_THROW( Invalid_Stream_Operation );
+ goto Exit;
+ }
+
+ if ( fields->value == ft_frame_bytes )
+ {
+ p = (FT_Byte*)structure + fields->offset;
+ FT_MEM_COPY( p, cursor, len );
+ }
+ cursor += len;
+ fields++;
+ continue;
+ }
+
+ case ft_frame_byte:
+ case ft_frame_schar: /* read a single byte */
+ value = FT_NEXT_BYTE( cursor );
+ sign_shift = 24;
+ break;
+
+ case ft_frame_short_be:
+ case ft_frame_ushort_be: /* read a 2-byte big-endian short */
+ value = FT_NEXT_USHORT( cursor) ;
+ sign_shift = 16;
+ break;
+
+ case ft_frame_short_le:
+ case ft_frame_ushort_le: /* read a 2-byte little-endian short */
+ value = FT_NEXT_USHORT_LE( cursor );
+ sign_shift = 16;
+ break;
+
+ case ft_frame_long_be:
+ case ft_frame_ulong_be: /* read a 4-byte big-endian long */
+ value = FT_NEXT_ULONG( cursor );
+ sign_shift = 0;
+ break;
+
+ case ft_frame_long_le:
+ case ft_frame_ulong_le: /* read a 4-byte little-endian long */
+ value = FT_NEXT_ULONG_LE( cursor );
+ sign_shift = 0;
+ break;
+
+ case ft_frame_off3_be:
+ case ft_frame_uoff3_be: /* read a 3-byte big-endian long */
+ value = FT_NEXT_UOFF3( cursor );
+ sign_shift = 8;
+ break;
+
+ case ft_frame_off3_le:
+ case ft_frame_uoff3_le: /* read a 3-byte little-endian long */
+ value = FT_NEXT_UOFF3_LE( cursor );
+ sign_shift = 8;
+ break;
+
+ default:
+ /* otherwise, exit the loop */
+ stream->cursor = cursor;
+ goto Exit;
+ }
+
+ /* now, compute the signed value is necessary */
+ if ( fields->value & FT_FRAME_OP_SIGNED )
+ value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
+
+ /* finally, store the value in the object */
+
+ p = (FT_Byte*)structure + fields->offset;
+ switch ( fields->size )
+ {
+ case ( 8 / FT_CHAR_BIT ):
+ *(FT_Byte*)p = (FT_Byte)value;
+ break;
+
+ case ( 16 / FT_CHAR_BIT ):
+ *(FT_UShort*)p = (FT_UShort)value;
+ break;
+
+ case ( 32 / FT_CHAR_BIT ):
+ *(FT_UInt32*)p = (FT_UInt32)value;
+ break;
+
+ default: /* for 64-bit systems */
+ *(FT_ULong*)p = (FT_ULong)value;
+ }
+
+ /* go to next field */
+ fields++;
+ }
+ while ( 1 );
+
+ Exit:
+ /* close the frame if it was opened by this read */
+ if ( frame_accessed )
+ FT_Stream_ExitFrame( stream );
+
+ return error;
+ }
+
+
+/* END */