1/****************************************************************************
2 *
3 * ftstream.c
4 *
5 * I/O stream support (body).
6 *
7 * Copyright (C) 2000-2019 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 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 = NULL;
43 stream->read = NULL;
44 stream->close = NULL;
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, stream->pos + (FT_ULong)distance );
99 }
100
101
102 FT_BASE_DEF( FT_ULong )
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 = NULL;
207 stream->limit = NULL;
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
223#ifdef FT_DEBUG_MEMORY
224 ft_mem_free( memory, *pbytes );
225#else
226 FT_FREE( *pbytes );
227#endif
228 }
229
230 *pbytes = NULL;
231 }
232
233
234 FT_BASE_DEF( FT_Error )
235 FT_Stream_EnterFrame( FT_Stream stream,
236 FT_ULong count )
237 {
238 FT_Error error = FT_Err_Ok;
239 FT_ULong read_bytes;
240
241
242 FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count ));
243
244 /* check for nested frame access */
245 FT_ASSERT( stream && stream->cursor == 0 );
246
247 if ( stream->read )
248 {
249 /* allocate the frame in memory */
250 FT_Memory memory = stream->memory;
251
252
253 /* simple sanity check */
254 if ( count > stream->size )
255 {
256 FT_ERROR(( "FT_Stream_EnterFrame:"
257 " frame size (%lu) larger than stream size (%lu)\n",
258 count, stream->size ));
259
260 error = FT_THROW( Invalid_Stream_Operation );
261 goto Exit;
262 }
263
264#ifdef FT_DEBUG_MEMORY
265 /* assume _ft_debug_file and _ft_debug_lineno are already set */
266 stream->base = (unsigned char*)ft_mem_qalloc( memory,
267 (FT_Long)count,
268 &error );
269 if ( error )
270 goto Exit;
271#else
272 if ( FT_QALLOC( stream->base, count ) )
273 goto Exit;
274#endif
275 /* read it */
276 read_bytes = stream->read( stream, stream->pos,
277 stream->base, count );
278 if ( read_bytes < count )
279 {
280 FT_ERROR(( "FT_Stream_EnterFrame:"
281 " invalid read; expected %lu bytes, got %lu\n",
282 count, read_bytes ));
283
284 FT_FREE( stream->base );
285 error = FT_THROW( Invalid_Stream_Operation );
286 }
287
288 stream->cursor = stream->base;
289 stream->limit = stream->cursor + count;
290 stream->pos += read_bytes;
291 }
292 else
293 {
294 /* check current and new position */
295 if ( stream->pos >= stream->size ||
296 stream->size - stream->pos < count )
297 {
298 FT_ERROR(( "FT_Stream_EnterFrame:"
299 " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
300 stream->pos, count, stream->size ));
301
302 error = FT_THROW( Invalid_Stream_Operation );
303 goto Exit;
304 }
305
306 /* set cursor */
307 stream->cursor = stream->base + stream->pos;
308 stream->limit = stream->cursor + count;
309 stream->pos += count;
310 }
311
312 Exit:
313 return error;
314 }
315
316
317 FT_BASE_DEF( void )
318 FT_Stream_ExitFrame( FT_Stream stream )
319 {
320 /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */
321 /* that it is possible to access a frame of length 0 in */
322 /* some weird fonts (usually, when accessing an array of */
323 /* 0 records, like in some strange kern tables). */
324 /* */
325 /* In this case, the loader code handles the 0-length table */
326 /* gracefully; however, stream.cursor is really set to 0 by the */
327 /* FT_Stream_EnterFrame() call, and this is not an error. */
328
329 FT_TRACE7(( "FT_Stream_ExitFrame\n" ));
330
331 FT_ASSERT( stream );
332
333 if ( stream->read )
334 {
335 FT_Memory memory = stream->memory;
336
337
338#ifdef FT_DEBUG_MEMORY
339 ft_mem_free( memory, stream->base );
340 stream->base = NULL;
341#else
342 FT_FREE( stream->base );
343#endif
344 }
345
346 stream->cursor = NULL;
347 stream->limit = NULL;
348 }
349
350
351 FT_BASE_DEF( FT_Char )
352 FT_Stream_GetChar( FT_Stream stream )
353 {
354 FT_Char result;
355
356
357 FT_ASSERT( stream && stream->cursor );
358
359 result = 0;
360 if ( stream->cursor < stream->limit )
361 result = (FT_Char)*stream->cursor++;
362
363 return result;
364 }
365
366
367 FT_BASE_DEF( FT_UShort )
368 FT_Stream_GetUShort( FT_Stream stream )
369 {
370 FT_Byte* p;
371 FT_UShort result;
372
373
374 FT_ASSERT( stream && stream->cursor );
375
376 result = 0;
377 p = stream->cursor;
378 if ( p + 1 < stream->limit )
379 result = FT_NEXT_USHORT( p );
380 stream->cursor = p;
381
382 return result;
383 }
384
385
386 FT_BASE_DEF( FT_UShort )
387 FT_Stream_GetUShortLE( FT_Stream stream )
388 {
389 FT_Byte* p;
390 FT_UShort result;
391
392
393 FT_ASSERT( stream && stream->cursor );
394
395 result = 0;
396 p = stream->cursor;
397 if ( p + 1 < stream->limit )
398 result = FT_NEXT_USHORT_LE( p );
399 stream->cursor = p;
400
401 return result;
402 }
403
404
405 FT_BASE_DEF( FT_ULong )
406 FT_Stream_GetUOffset( FT_Stream stream )
407 {
408 FT_Byte* p;
409 FT_ULong result;
410
411
412 FT_ASSERT( stream && stream->cursor );
413
414 result = 0;
415 p = stream->cursor;
416 if ( p + 2 < stream->limit )
417 result = FT_NEXT_UOFF3( p );
418 stream->cursor = p;
419 return result;
420 }
421
422
423 FT_BASE_DEF( FT_ULong )
424 FT_Stream_GetULong( FT_Stream stream )
425 {
426 FT_Byte* p;
427 FT_ULong result;
428
429
430 FT_ASSERT( stream && stream->cursor );
431
432 result = 0;
433 p = stream->cursor;
434 if ( p + 3 < stream->limit )
435 result = FT_NEXT_ULONG( p );
436 stream->cursor = p;
437 return result;
438 }
439
440
441 FT_BASE_DEF( FT_ULong )
442 FT_Stream_GetULongLE( FT_Stream stream )
443 {
444 FT_Byte* p;
445 FT_ULong result;
446
447
448 FT_ASSERT( stream && stream->cursor );
449
450 result = 0;
451 p = stream->cursor;
452 if ( p + 3 < stream->limit )
453 result = FT_NEXT_ULONG_LE( p );
454 stream->cursor = p;
455 return result;
456 }
457
458
459 FT_BASE_DEF( FT_Char )
460 FT_Stream_ReadChar( FT_Stream stream,
461 FT_Error* error )
462 {
463 FT_Byte result = 0;
464
465
466 FT_ASSERT( stream );
467
468 *error = FT_Err_Ok;
469
470 if ( stream->read )
471 {
472 if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
473 goto Fail;
474 }
475 else
476 {
477 if ( stream->pos < stream->size )
478 result = stream->base[stream->pos];
479 else
480 goto Fail;
481 }
482 stream->pos++;
483
484 return (FT_Char)result;
485
486 Fail:
487 *error = FT_THROW( Invalid_Stream_Operation );
488 FT_ERROR(( "FT_Stream_ReadChar:"
489 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
490 stream->pos, stream->size ));
491
492 return 0;
493 }
494
495
496 FT_BASE_DEF( FT_UShort )
497 FT_Stream_ReadUShort( FT_Stream stream,
498 FT_Error* error )
499 {
500 FT_Byte reads[2];
501 FT_Byte* p = 0;
502 FT_UShort result = 0;
503
504
505 FT_ASSERT( stream );
506
507 *error = FT_Err_Ok;
508
509 if ( stream->pos + 1 < stream->size )
510 {
511 if ( stream->read )
512 {
513 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
514 goto Fail;
515
516 p = reads;
517 }
518 else
519 p = stream->base + stream->pos;
520
521 if ( p )
522 result = FT_NEXT_USHORT( p );
523 }
524 else
525 goto Fail;
526
527 stream->pos += 2;
528
529 return result;
530
531 Fail:
532 *error = FT_THROW( Invalid_Stream_Operation );
533 FT_ERROR(( "FT_Stream_ReadUShort:"
534 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
535 stream->pos, stream->size ));
536
537 return 0;
538 }
539
540
541 FT_BASE_DEF( FT_UShort )
542 FT_Stream_ReadUShortLE( FT_Stream stream,
543 FT_Error* error )
544 {
545 FT_Byte reads[2];
546 FT_Byte* p = 0;
547 FT_UShort result = 0;
548
549
550 FT_ASSERT( stream );
551
552 *error = FT_Err_Ok;
553
554 if ( stream->pos + 1 < stream->size )
555 {
556 if ( stream->read )
557 {
558 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
559 goto Fail;
560
561 p = reads;
562 }
563 else
564 p = stream->base + stream->pos;
565
566 if ( p )
567 result = FT_NEXT_USHORT_LE( p );
568 }
569 else
570 goto Fail;
571
572 stream->pos += 2;
573
574 return result;
575
576 Fail:
577 *error = FT_THROW( Invalid_Stream_Operation );
578 FT_ERROR(( "FT_Stream_ReadUShortLE:"
579 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
580 stream->pos, stream->size ));
581
582 return 0;
583 }
584
585
586 FT_BASE_DEF( FT_ULong )
587 FT_Stream_ReadUOffset( FT_Stream stream,
588 FT_Error* error )
589 {
590 FT_Byte reads[3];
591 FT_Byte* p = 0;
592 FT_ULong result = 0;
593
594
595 FT_ASSERT( stream );
596
597 *error = FT_Err_Ok;
598
599 if ( stream->pos + 2 < stream->size )
600 {
601 if ( stream->read )
602 {
603 if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
604 goto Fail;
605
606 p = reads;
607 }
608 else
609 p = stream->base + stream->pos;
610
611 if ( p )
612 result = FT_NEXT_UOFF3( p );
613 }
614 else
615 goto Fail;
616
617 stream->pos += 3;
618
619 return result;
620
621 Fail:
622 *error = FT_THROW( Invalid_Stream_Operation );
623 FT_ERROR(( "FT_Stream_ReadUOffset:"
624 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
625 stream->pos, stream->size ));
626
627 return 0;
628 }
629
630
631 FT_BASE_DEF( FT_ULong )
632 FT_Stream_ReadULong( FT_Stream stream,
633 FT_Error* error )
634 {
635 FT_Byte reads[4];
636 FT_Byte* p = 0;
637 FT_ULong result = 0;
638
639
640 FT_ASSERT( stream );
641
642 *error = FT_Err_Ok;
643
644 if ( stream->pos + 3 < stream->size )
645 {
646 if ( stream->read )
647 {
648 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
649 goto Fail;
650
651 p = reads;
652 }
653 else
654 p = stream->base + stream->pos;
655
656 if ( p )
657 result = FT_NEXT_ULONG( p );
658 }
659 else
660 goto Fail;
661
662 stream->pos += 4;
663
664 return result;
665
666 Fail:
667 *error = FT_THROW( Invalid_Stream_Operation );
668 FT_ERROR(( "FT_Stream_ReadULong:"
669 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
670 stream->pos, stream->size ));
671
672 return 0;
673 }
674
675
676 FT_BASE_DEF( FT_ULong )
677 FT_Stream_ReadULongLE( FT_Stream stream,
678 FT_Error* error )
679 {
680 FT_Byte reads[4];
681 FT_Byte* p = 0;
682 FT_ULong result = 0;
683
684
685 FT_ASSERT( stream );
686
687 *error = FT_Err_Ok;
688
689 if ( stream->pos + 3 < stream->size )
690 {
691 if ( stream->read )
692 {
693 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
694 goto Fail;
695
696 p = reads;
697 }
698 else
699 p = stream->base + stream->pos;
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 )
732 return FT_THROW( Invalid_Argument );
733
734 if ( !stream )
735 return FT_THROW( Invalid_Stream_Handle );
736
737 cursor = stream->cursor;
738
739 error = FT_Err_Ok;
740 do
741 {
742 FT_ULong value;
743 FT_Int sign_shift;
744 FT_Byte* p;
745
746
747 switch ( fields->value )
748 {
749 case ft_frame_start: /* access a new frame */
750 error = FT_Stream_EnterFrame( stream, fields->offset );
751 if ( error )
752 goto Exit;
753
754 frame_accessed = 1;
755 cursor = stream->cursor;
756 fields++;
757 continue; /* loop! */
758
759 case ft_frame_bytes: /* read a byte sequence */
760 case ft_frame_skip: /* skip some bytes */
761 {
762 FT_UInt len = fields->size;
763
764
765 if ( cursor + len > stream->limit )
766 {
767 error = FT_THROW( Invalid_Stream_Operation );
768 goto Exit;
769 }
770
771 if ( fields->value == ft_frame_bytes )
772 {
773 p = (FT_Byte*)structure + fields->offset;
774 FT_MEM_COPY( p, cursor, len );
775 }
776 cursor += len;
777 fields++;
778 continue;
779 }
780
781 case ft_frame_byte:
782 case ft_frame_schar: /* read a single byte */
783 value = FT_NEXT_BYTE( cursor );
784 sign_shift = 24;
785 break;
786
787 case ft_frame_short_be:
788 case ft_frame_ushort_be: /* read a 2-byte big-endian short */
789 value = FT_NEXT_USHORT( cursor );
790 sign_shift = 16;
791 break;
792
793 case ft_frame_short_le:
794 case ft_frame_ushort_le: /* read a 2-byte little-endian short */
795 value = FT_NEXT_USHORT_LE( cursor );
796 sign_shift = 16;
797 break;
798
799 case ft_frame_long_be:
800 case ft_frame_ulong_be: /* read a 4-byte big-endian long */
801 value = FT_NEXT_ULONG( cursor );
802 sign_shift = 0;
803 break;
804
805 case ft_frame_long_le:
806 case ft_frame_ulong_le: /* read a 4-byte little-endian long */
807 value = FT_NEXT_ULONG_LE( cursor );
808 sign_shift = 0;
809 break;
810
811 case ft_frame_off3_be:
812 case ft_frame_uoff3_be: /* read a 3-byte big-endian long */
813 value = FT_NEXT_UOFF3( cursor );
814 sign_shift = 8;
815 break;
816
817 case ft_frame_off3_le:
818 case ft_frame_uoff3_le: /* read a 3-byte little-endian long */
819 value = FT_NEXT_UOFF3_LE( cursor );
820 sign_shift = 8;
821 break;
822
823 default:
824 /* otherwise, exit the loop */
825 stream->cursor = cursor;
826 goto Exit;
827 }
828
829 /* now, compute the signed value is necessary */
830 if ( fields->value & FT_FRAME_OP_SIGNED )
831 value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
832
833 /* finally, store the value in the object */
834
835 p = (FT_Byte*)structure + fields->offset;
836 switch ( fields->size )
837 {
838 case ( 8 / FT_CHAR_BIT ):
839 *(FT_Byte*)p = (FT_Byte)value;
840 break;
841
842 case ( 16 / FT_CHAR_BIT ):
843 *(FT_UShort*)p = (FT_UShort)value;
844 break;
845
846 case ( 32 / FT_CHAR_BIT ):
847 *(FT_UInt32*)p = (FT_UInt32)value;
848 break;
849
850 default: /* for 64-bit systems */
851 *(FT_ULong*)p = (FT_ULong)value;
852 }
853
854 /* go to next field */
855 fields++;
856 }
857 while ( 1 );
858
859 Exit:
860 /* close the frame if it was opened by this read */
861 if ( frame_accessed )
862 FT_Stream_ExitFrame( stream );
863
864 return error;
865 }
866
867
868/* END */
869