1 /****************************************************************************
5 * I/O stream support (body).
7 * Copyright (C) 2000-2020 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
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.
19 #include <freetype/internal/ftstream.h>
20 #include <freetype/internal/ftdebug.h>
23 /**************************************************************************
25 * The macro FT_COMPONENT is used in trace mode. It is an implicit
26 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
27 * messages during execution.
30 #define FT_COMPONENT stream
34 FT_Stream_OpenMemory( FT_Stream stream,
38 stream->base = (FT_Byte*) base;
41 stream->cursor = NULL;
48 FT_Stream_Close( FT_Stream stream )
50 if ( stream && stream->close )
51 stream->close( stream );
55 FT_BASE_DEF( FT_Error )
56 FT_Stream_Seek( FT_Stream stream,
59 FT_Error error = FT_Err_Ok;
64 if ( stream->read( stream, pos, 0, 0 ) )
66 FT_ERROR(( "FT_Stream_Seek:"
67 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
70 error = FT_THROW( Invalid_Stream_Operation );
73 /* note that seeking to the first position after the file is valid */
74 else if ( pos > stream->size )
76 FT_ERROR(( "FT_Stream_Seek:"
77 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
80 error = FT_THROW( Invalid_Stream_Operation );
90 FT_BASE_DEF( FT_Error )
91 FT_Stream_Skip( FT_Stream stream,
95 return FT_THROW( Invalid_Stream_Operation );
97 return FT_Stream_Seek( stream, stream->pos + (FT_ULong)distance );
101 FT_BASE_DEF( FT_ULong )
102 FT_Stream_Pos( FT_Stream stream )
108 FT_BASE_DEF( FT_Error )
109 FT_Stream_Read( FT_Stream stream,
113 return FT_Stream_ReadAt( stream, stream->pos, buffer, count );
117 FT_BASE_DEF( FT_Error )
118 FT_Stream_ReadAt( FT_Stream stream,
123 FT_Error error = FT_Err_Ok;
127 if ( pos >= stream->size )
129 FT_ERROR(( "FT_Stream_ReadAt:"
130 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
131 pos, stream->size ));
133 return FT_THROW( Invalid_Stream_Operation );
137 read_bytes = stream->read( stream, pos, buffer, count );
140 read_bytes = stream->size - pos;
141 if ( read_bytes > count )
144 FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
147 stream->pos = pos + read_bytes;
149 if ( read_bytes < count )
151 FT_ERROR(( "FT_Stream_ReadAt:"
152 " invalid read; expected %lu bytes, got %lu\n",
153 count, read_bytes ));
155 error = FT_THROW( Invalid_Stream_Operation );
162 FT_BASE_DEF( FT_ULong )
163 FT_Stream_TryRead( FT_Stream stream,
167 FT_ULong read_bytes = 0;
170 if ( stream->pos >= stream->size )
174 read_bytes = stream->read( stream, stream->pos, buffer, count );
177 read_bytes = stream->size - stream->pos;
178 if ( read_bytes > count )
181 FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
184 stream->pos += read_bytes;
191 FT_BASE_DEF( FT_Error )
192 FT_Stream_ExtractFrame( FT_Stream stream,
199 error = FT_Stream_EnterFrame( stream, count );
202 *pbytes = (FT_Byte*)stream->cursor;
204 /* equivalent to FT_Stream_ExitFrame(), with no memory block release */
205 stream->cursor = NULL;
206 stream->limit = NULL;
214 FT_Stream_ReleaseFrame( FT_Stream stream,
217 if ( stream && stream->read )
219 FT_Memory memory = stream->memory;
222 #ifdef FT_DEBUG_MEMORY
223 ft_mem_free( memory, *pbytes );
233 FT_BASE_DEF( FT_Error )
234 FT_Stream_EnterFrame( FT_Stream stream,
237 FT_Error error = FT_Err_Ok;
241 FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count ));
243 /* check for nested frame access */
244 FT_ASSERT( stream && stream->cursor == 0 );
248 /* allocate the frame in memory */
249 FT_Memory memory = stream->memory;
252 /* simple sanity check */
253 if ( count > stream->size )
255 FT_ERROR(( "FT_Stream_EnterFrame:"
256 " frame size (%lu) larger than stream size (%lu)\n",
257 count, stream->size ));
259 error = FT_THROW( Invalid_Stream_Operation );
263 #ifdef FT_DEBUG_MEMORY
264 /* assume _ft_debug_file and _ft_debug_lineno are already set */
265 stream->base = (unsigned char*)ft_mem_qalloc( memory,
271 if ( FT_QALLOC( stream->base, count ) )
275 read_bytes = stream->read( stream, stream->pos,
276 stream->base, count );
277 if ( read_bytes < count )
279 FT_ERROR(( "FT_Stream_EnterFrame:"
280 " invalid read; expected %lu bytes, got %lu\n",
281 count, read_bytes ));
283 FT_FREE( stream->base );
284 error = FT_THROW( Invalid_Stream_Operation );
287 stream->cursor = stream->base;
288 stream->limit = FT_OFFSET( stream->cursor, count );
289 stream->pos += read_bytes;
293 /* check current and new position */
294 if ( stream->pos >= stream->size ||
295 stream->size - stream->pos < count )
297 FT_ERROR(( "FT_Stream_EnterFrame:"
298 " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
299 stream->pos, count, stream->size ));
301 error = FT_THROW( Invalid_Stream_Operation );
306 stream->cursor = stream->base + stream->pos;
307 stream->limit = stream->cursor + count;
308 stream->pos += count;
317 FT_Stream_ExitFrame( FT_Stream stream )
319 /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */
320 /* that it is possible to access a frame of length 0 in */
321 /* some weird fonts (usually, when accessing an array of */
322 /* 0 records, like in some strange kern tables). */
324 /* In this case, the loader code handles the 0-length table */
325 /* gracefully; however, stream.cursor is really set to 0 by the */
326 /* FT_Stream_EnterFrame() call, and this is not an error. */
328 FT_TRACE7(( "FT_Stream_ExitFrame\n" ));
334 FT_Memory memory = stream->memory;
337 #ifdef FT_DEBUG_MEMORY
338 ft_mem_free( memory, stream->base );
341 FT_FREE( stream->base );
345 stream->cursor = NULL;
346 stream->limit = NULL;
350 FT_BASE_DEF( FT_Char )
351 FT_Stream_GetChar( FT_Stream stream )
356 FT_ASSERT( stream && stream->cursor );
359 if ( stream->cursor < stream->limit )
360 result = (FT_Char)*stream->cursor++;
366 FT_BASE_DEF( FT_UShort )
367 FT_Stream_GetUShort( FT_Stream stream )
373 FT_ASSERT( stream && stream->cursor );
377 if ( p + 1 < stream->limit )
378 result = FT_NEXT_USHORT( p );
385 FT_BASE_DEF( FT_UShort )
386 FT_Stream_GetUShortLE( FT_Stream stream )
392 FT_ASSERT( stream && stream->cursor );
396 if ( p + 1 < stream->limit )
397 result = FT_NEXT_USHORT_LE( p );
404 FT_BASE_DEF( FT_ULong )
405 FT_Stream_GetUOffset( FT_Stream stream )
411 FT_ASSERT( stream && stream->cursor );
415 if ( p + 2 < stream->limit )
416 result = FT_NEXT_UOFF3( p );
422 FT_BASE_DEF( FT_ULong )
423 FT_Stream_GetULong( FT_Stream stream )
429 FT_ASSERT( stream && stream->cursor );
433 if ( p + 3 < stream->limit )
434 result = FT_NEXT_ULONG( p );
440 FT_BASE_DEF( FT_ULong )
441 FT_Stream_GetULongLE( FT_Stream stream )
447 FT_ASSERT( stream && stream->cursor );
451 if ( p + 3 < stream->limit )
452 result = FT_NEXT_ULONG_LE( p );
458 FT_BASE_DEF( FT_Char )
459 FT_Stream_ReadChar( FT_Stream stream,
471 if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
476 if ( stream->pos < stream->size )
477 result = stream->base[stream->pos];
483 return (FT_Char)result;
486 *error = FT_THROW( Invalid_Stream_Operation );
487 FT_ERROR(( "FT_Stream_ReadChar:"
488 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
489 stream->pos, stream->size ));
495 FT_BASE_DEF( FT_UShort )
496 FT_Stream_ReadUShort( FT_Stream stream,
501 FT_UShort result = 0;
508 if ( stream->pos + 1 < stream->size )
512 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
518 p = stream->base + stream->pos;
521 result = FT_NEXT_USHORT( p );
531 *error = FT_THROW( Invalid_Stream_Operation );
532 FT_ERROR(( "FT_Stream_ReadUShort:"
533 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
534 stream->pos, stream->size ));
540 FT_BASE_DEF( FT_UShort )
541 FT_Stream_ReadUShortLE( FT_Stream stream,
546 FT_UShort result = 0;
553 if ( stream->pos + 1 < stream->size )
557 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
563 p = stream->base + stream->pos;
566 result = FT_NEXT_USHORT_LE( p );
576 *error = FT_THROW( Invalid_Stream_Operation );
577 FT_ERROR(( "FT_Stream_ReadUShortLE:"
578 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
579 stream->pos, stream->size ));
585 FT_BASE_DEF( FT_ULong )
586 FT_Stream_ReadUOffset( FT_Stream stream,
598 if ( stream->pos + 2 < stream->size )
602 if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
608 p = stream->base + stream->pos;
611 result = FT_NEXT_UOFF3( p );
621 *error = FT_THROW( Invalid_Stream_Operation );
622 FT_ERROR(( "FT_Stream_ReadUOffset:"
623 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
624 stream->pos, stream->size ));
630 FT_BASE_DEF( FT_ULong )
631 FT_Stream_ReadULong( FT_Stream stream,
643 if ( stream->pos + 3 < stream->size )
647 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
653 p = stream->base + stream->pos;
656 result = FT_NEXT_ULONG( p );
666 *error = FT_THROW( Invalid_Stream_Operation );
667 FT_ERROR(( "FT_Stream_ReadULong:"
668 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
669 stream->pos, stream->size ));
675 FT_BASE_DEF( FT_ULong )
676 FT_Stream_ReadULongLE( FT_Stream stream,
688 if ( stream->pos + 3 < stream->size )
692 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
698 p = stream->base + stream->pos;
701 result = FT_NEXT_ULONG_LE( p );
711 *error = FT_THROW( Invalid_Stream_Operation );
712 FT_ERROR(( "FT_Stream_ReadULongLE:"
713 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
714 stream->pos, stream->size ));
720 FT_BASE_DEF( FT_Error )
721 FT_Stream_ReadFields( FT_Stream stream,
722 const FT_Frame_Field* fields,
726 FT_Bool frame_accessed = 0;
731 return FT_THROW( Invalid_Argument );
734 return FT_THROW( Invalid_Stream_Handle );
736 cursor = stream->cursor;
746 switch ( fields->value )
748 case ft_frame_start: /* access a new frame */
749 error = FT_Stream_EnterFrame( stream, fields->offset );
754 cursor = stream->cursor;
756 continue; /* loop! */
758 case ft_frame_bytes: /* read a byte sequence */
759 case ft_frame_skip: /* skip some bytes */
761 FT_UInt len = fields->size;
764 if ( cursor + len > stream->limit )
766 error = FT_THROW( Invalid_Stream_Operation );
770 if ( fields->value == ft_frame_bytes )
772 p = (FT_Byte*)structure + fields->offset;
773 FT_MEM_COPY( p, cursor, len );
781 case ft_frame_schar: /* read a single byte */
782 value = FT_NEXT_BYTE( cursor );
786 case ft_frame_short_be:
787 case ft_frame_ushort_be: /* read a 2-byte big-endian short */
788 value = FT_NEXT_USHORT( cursor );
792 case ft_frame_short_le:
793 case ft_frame_ushort_le: /* read a 2-byte little-endian short */
794 value = FT_NEXT_USHORT_LE( cursor );
798 case ft_frame_long_be:
799 case ft_frame_ulong_be: /* read a 4-byte big-endian long */
800 value = FT_NEXT_ULONG( cursor );
804 case ft_frame_long_le:
805 case ft_frame_ulong_le: /* read a 4-byte little-endian long */
806 value = FT_NEXT_ULONG_LE( cursor );
810 case ft_frame_off3_be:
811 case ft_frame_uoff3_be: /* read a 3-byte big-endian long */
812 value = FT_NEXT_UOFF3( cursor );
816 case ft_frame_off3_le:
817 case ft_frame_uoff3_le: /* read a 3-byte little-endian long */
818 value = FT_NEXT_UOFF3_LE( cursor );
823 /* otherwise, exit the loop */
824 stream->cursor = cursor;
828 /* now, compute the signed value is necessary */
829 if ( fields->value & FT_FRAME_OP_SIGNED )
830 value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
832 /* finally, store the value in the object */
834 p = (FT_Byte*)structure + fields->offset;
835 switch ( fields->size )
837 case ( 8 / FT_CHAR_BIT ):
838 *(FT_Byte*)p = (FT_Byte)value;
841 case ( 16 / FT_CHAR_BIT ):
842 *(FT_UShort*)p = (FT_UShort)value;
845 case ( 32 / FT_CHAR_BIT ):
846 *(FT_UInt32*)p = (FT_UInt32)value;
849 default: /* for 64-bit systems */
850 *(FT_ULong*)p = (FT_ULong)value;
853 /* go to next field */
859 /* close the frame if it was opened by this read */
860 if ( frame_accessed )
861 FT_Stream_ExitFrame( stream );