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