d940254d8bb744c13d877df543523cb6691a3925
[platform/upstream/freetype2.git] / src / base / ftstream.c
1 /****************************************************************************
2  *
3  * ftstream.c
4  *
5  *   I/O stream support (body).
6  *
7  * Copyright (C) 2000-2020 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, 0, 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       FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
145     }
146
147     stream->pos = pos + read_bytes;
148
149     if ( read_bytes < count )
150     {
151       FT_ERROR(( "FT_Stream_ReadAt:"
152                  " invalid read; expected %lu bytes, got %lu\n",
153                  count, read_bytes ));
154
155       error = FT_THROW( Invalid_Stream_Operation );
156     }
157
158     return error;
159   }
160
161
162   FT_BASE_DEF( FT_ULong )
163   FT_Stream_TryRead( FT_Stream  stream,
164                      FT_Byte*   buffer,
165                      FT_ULong   count )
166   {
167     FT_ULong  read_bytes = 0;
168
169
170     if ( stream->pos >= stream->size )
171       goto Exit;
172
173     if ( stream->read )
174       read_bytes = stream->read( stream, stream->pos, buffer, count );
175     else
176     {
177       read_bytes = stream->size - stream->pos;
178       if ( read_bytes > count )
179         read_bytes = count;
180
181       FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
182     }
183
184     stream->pos += read_bytes;
185
186   Exit:
187     return read_bytes;
188   }
189
190
191   FT_BASE_DEF( FT_Error )
192   FT_Stream_ExtractFrame( FT_Stream  stream,
193                           FT_ULong   count,
194                           FT_Byte**  pbytes )
195   {
196     FT_Error  error;
197
198
199     error = FT_Stream_EnterFrame( stream, count );
200     if ( !error )
201     {
202       *pbytes = (FT_Byte*)stream->cursor;
203
204       /* equivalent to FT_Stream_ExitFrame(), with no memory block release */
205       stream->cursor = NULL;
206       stream->limit  = NULL;
207     }
208
209     return error;
210   }
211
212
213   FT_BASE_DEF( void )
214   FT_Stream_ReleaseFrame( FT_Stream  stream,
215                           FT_Byte**  pbytes )
216   {
217     if ( stream && stream->read )
218     {
219       FT_Memory  memory = stream->memory;
220
221
222 #ifdef FT_DEBUG_MEMORY
223       ft_mem_free( memory, *pbytes );
224 #else
225       FT_FREE( *pbytes );
226 #endif
227     }
228
229     *pbytes = NULL;
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     FT_TRACE7(( "FT_Stream_EnterFrame: %ld bytes\n", count ));
242
243     /* check for nested frame access */
244     FT_ASSERT( stream && stream->cursor == 0 );
245
246     if ( stream->read )
247     {
248       /* allocate the frame in memory */
249       FT_Memory  memory = stream->memory;
250
251
252       /* simple sanity check */
253       if ( count > stream->size )
254       {
255         FT_ERROR(( "FT_Stream_EnterFrame:"
256                    " frame size (%lu) larger than stream size (%lu)\n",
257                    count, stream->size ));
258
259         error = FT_THROW( Invalid_Stream_Operation );
260         goto Exit;
261       }
262
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,
266                                                     (FT_Long)count,
267                                                     &error );
268       if ( error )
269         goto Exit;
270 #else
271       if ( FT_QALLOC( stream->base, count ) )
272         goto Exit;
273 #endif
274       /* read it */
275       read_bytes = stream->read( stream, stream->pos,
276                                  stream->base, count );
277       if ( read_bytes < count )
278       {
279         FT_ERROR(( "FT_Stream_EnterFrame:"
280                    " invalid read; expected %lu bytes, got %lu\n",
281                    count, read_bytes ));
282
283         FT_FREE( stream->base );
284         error = FT_THROW( Invalid_Stream_Operation );
285       }
286
287       stream->cursor = stream->base;
288       stream->limit  = FT_OFFSET( stream->cursor, count );
289       stream->pos   += read_bytes;
290     }
291     else
292     {
293       /* check current and new position */
294       if ( stream->pos >= stream->size        ||
295            stream->size - stream->pos < count )
296       {
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 ));
300
301         error = FT_THROW( Invalid_Stream_Operation );
302         goto Exit;
303       }
304
305       /* set cursor */
306       stream->cursor = stream->base + stream->pos;
307       stream->limit  = stream->cursor + count;
308       stream->pos   += count;
309     }
310
311   Exit:
312     return error;
313   }
314
315
316   FT_BASE_DEF( void )
317   FT_Stream_ExitFrame( FT_Stream  stream )
318   {
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).           */
323     /*                                                                    */
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.            */
327
328     FT_TRACE7(( "FT_Stream_ExitFrame\n" ));
329
330     FT_ASSERT( stream );
331
332     if ( stream->read )
333     {
334       FT_Memory  memory = stream->memory;
335
336
337 #ifdef FT_DEBUG_MEMORY
338       ft_mem_free( memory, stream->base );
339       stream->base = NULL;
340 #else
341       FT_FREE( stream->base );
342 #endif
343     }
344
345     stream->cursor = NULL;
346     stream->limit  = NULL;
347   }
348
349
350   FT_BASE_DEF( FT_Char )
351   FT_Stream_GetChar( FT_Stream  stream )
352   {
353     FT_Char  result;
354
355
356     FT_ASSERT( stream && stream->cursor );
357
358     result = 0;
359     if ( stream->cursor < stream->limit )
360       result = (FT_Char)*stream->cursor++;
361
362     return result;
363   }
364
365
366   FT_BASE_DEF( FT_UShort )
367   FT_Stream_GetUShort( FT_Stream  stream )
368   {
369     FT_Byte*   p;
370     FT_UShort  result;
371
372
373     FT_ASSERT( stream && stream->cursor );
374
375     result         = 0;
376     p              = stream->cursor;
377     if ( p + 1 < stream->limit )
378       result       = FT_NEXT_USHORT( p );
379     stream->cursor = p;
380
381     return result;
382   }
383
384
385   FT_BASE_DEF( FT_UShort )
386   FT_Stream_GetUShortLE( FT_Stream  stream )
387   {
388     FT_Byte*   p;
389     FT_UShort  result;
390
391
392     FT_ASSERT( stream && stream->cursor );
393
394     result         = 0;
395     p              = stream->cursor;
396     if ( p + 1 < stream->limit )
397       result       = FT_NEXT_USHORT_LE( p );
398     stream->cursor = p;
399
400     return result;
401   }
402
403
404   FT_BASE_DEF( FT_ULong )
405   FT_Stream_GetUOffset( FT_Stream  stream )
406   {
407     FT_Byte*  p;
408     FT_ULong  result;
409
410
411     FT_ASSERT( stream && stream->cursor );
412
413     result         = 0;
414     p              = stream->cursor;
415     if ( p + 2 < stream->limit )
416       result       = FT_NEXT_UOFF3( p );
417     stream->cursor = p;
418     return result;
419   }
420
421
422   FT_BASE_DEF( FT_ULong )
423   FT_Stream_GetULong( FT_Stream  stream )
424   {
425     FT_Byte*  p;
426     FT_ULong  result;
427
428
429     FT_ASSERT( stream && stream->cursor );
430
431     result         = 0;
432     p              = stream->cursor;
433     if ( p + 3 < stream->limit )
434       result       = FT_NEXT_ULONG( p );
435     stream->cursor = p;
436     return result;
437   }
438
439
440   FT_BASE_DEF( FT_ULong )
441   FT_Stream_GetULongLE( FT_Stream  stream )
442   {
443     FT_Byte*  p;
444     FT_ULong  result;
445
446
447     FT_ASSERT( stream && stream->cursor );
448
449     result         = 0;
450     p              = stream->cursor;
451     if ( p + 3 < stream->limit )
452       result       = FT_NEXT_ULONG_LE( p );
453     stream->cursor = p;
454     return result;
455   }
456
457
458   FT_BASE_DEF( FT_Char )
459   FT_Stream_ReadChar( FT_Stream  stream,
460                       FT_Error*  error )
461   {
462     FT_Byte  result = 0;
463
464
465     FT_ASSERT( stream );
466
467     *error = FT_Err_Ok;
468
469     if ( stream->read )
470     {
471       if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
472         goto Fail;
473     }
474     else
475     {
476       if ( stream->pos < stream->size )
477         result = stream->base[stream->pos];
478       else
479         goto Fail;
480     }
481     stream->pos++;
482
483     return (FT_Char)result;
484
485   Fail:
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 ));
490
491     return 0;
492   }
493
494
495   FT_BASE_DEF( FT_UShort )
496   FT_Stream_ReadUShort( FT_Stream  stream,
497                         FT_Error*  error )
498   {
499     FT_Byte    reads[2];
500     FT_Byte*   p      = 0;
501     FT_UShort  result = 0;
502
503
504     FT_ASSERT( stream );
505
506     *error = FT_Err_Ok;
507
508     if ( stream->pos + 1 < stream->size )
509     {
510       if ( stream->read )
511       {
512         if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
513           goto Fail;
514
515         p = reads;
516       }
517       else
518         p = stream->base + stream->pos;
519
520       if ( p )
521         result = FT_NEXT_USHORT( p );
522     }
523     else
524       goto Fail;
525
526     stream->pos += 2;
527
528     return result;
529
530   Fail:
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 ));
535
536     return 0;
537   }
538
539
540   FT_BASE_DEF( FT_UShort )
541   FT_Stream_ReadUShortLE( FT_Stream  stream,
542                           FT_Error*  error )
543   {
544     FT_Byte    reads[2];
545     FT_Byte*   p      = 0;
546     FT_UShort  result = 0;
547
548
549     FT_ASSERT( stream );
550
551     *error = FT_Err_Ok;
552
553     if ( stream->pos + 1 < stream->size )
554     {
555       if ( stream->read )
556       {
557         if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
558           goto Fail;
559
560         p = reads;
561       }
562       else
563         p = stream->base + stream->pos;
564
565       if ( p )
566         result = FT_NEXT_USHORT_LE( p );
567     }
568     else
569       goto Fail;
570
571     stream->pos += 2;
572
573     return result;
574
575   Fail:
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 ));
580
581     return 0;
582   }
583
584
585   FT_BASE_DEF( FT_ULong )
586   FT_Stream_ReadUOffset( FT_Stream  stream,
587                          FT_Error*  error )
588   {
589     FT_Byte   reads[3];
590     FT_Byte*  p      = 0;
591     FT_ULong  result = 0;
592
593
594     FT_ASSERT( stream );
595
596     *error = FT_Err_Ok;
597
598     if ( stream->pos + 2 < stream->size )
599     {
600       if ( stream->read )
601       {
602         if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
603           goto Fail;
604
605         p = reads;
606       }
607       else
608         p = stream->base + stream->pos;
609
610       if ( p )
611         result = FT_NEXT_UOFF3( p );
612     }
613     else
614       goto Fail;
615
616     stream->pos += 3;
617
618     return result;
619
620   Fail:
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 ));
625
626     return 0;
627   }
628
629
630   FT_BASE_DEF( FT_ULong )
631   FT_Stream_ReadULong( FT_Stream  stream,
632                        FT_Error*  error )
633   {
634     FT_Byte   reads[4];
635     FT_Byte*  p      = 0;
636     FT_ULong  result = 0;
637
638
639     FT_ASSERT( stream );
640
641     *error = FT_Err_Ok;
642
643     if ( stream->pos + 3 < stream->size )
644     {
645       if ( stream->read )
646       {
647         if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
648           goto Fail;
649
650         p = reads;
651       }
652       else
653         p = stream->base + stream->pos;
654
655       if ( p )
656         result = FT_NEXT_ULONG( p );
657     }
658     else
659       goto Fail;
660
661     stream->pos += 4;
662
663     return result;
664
665   Fail:
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 ));
670
671     return 0;
672   }
673
674
675   FT_BASE_DEF( FT_ULong )
676   FT_Stream_ReadULongLE( FT_Stream  stream,
677                          FT_Error*  error )
678   {
679     FT_Byte   reads[4];
680     FT_Byte*  p      = 0;
681     FT_ULong  result = 0;
682
683
684     FT_ASSERT( stream );
685
686     *error = FT_Err_Ok;
687
688     if ( stream->pos + 3 < stream->size )
689     {
690       if ( stream->read )
691       {
692         if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
693           goto Fail;
694
695         p = reads;
696       }
697       else
698         p = stream->base + stream->pos;
699
700       if ( p )
701         result = FT_NEXT_ULONG_LE( p );
702     }
703     else
704       goto Fail;
705
706     stream->pos += 4;
707
708     return result;
709
710   Fail:
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 ));
715
716     return 0;
717   }
718
719
720   FT_BASE_DEF( FT_Error )
721   FT_Stream_ReadFields( FT_Stream              stream,
722                         const FT_Frame_Field*  fields,
723                         void*                  structure )
724   {
725     FT_Error  error;
726     FT_Bool   frame_accessed = 0;
727     FT_Byte*  cursor;
728
729
730     if ( !fields )
731       return FT_THROW( Invalid_Argument );
732
733     if ( !stream )
734       return FT_THROW( Invalid_Stream_Handle );
735
736     cursor = stream->cursor;
737
738     error = FT_Err_Ok;
739     do
740     {
741       FT_ULong  value;
742       FT_Int    sign_shift;
743       FT_Byte*  p;
744
745
746       switch ( fields->value )
747       {
748       case ft_frame_start:  /* access a new frame */
749         error = FT_Stream_EnterFrame( stream, fields->offset );
750         if ( error )
751           goto Exit;
752
753         frame_accessed = 1;
754         cursor         = stream->cursor;
755         fields++;
756         continue;  /* loop! */
757
758       case ft_frame_bytes:  /* read a byte sequence */
759       case ft_frame_skip:   /* skip some bytes      */
760         {
761           FT_UInt  len = fields->size;
762
763
764           if ( cursor + len > stream->limit )
765           {
766             error = FT_THROW( Invalid_Stream_Operation );
767             goto Exit;
768           }
769
770           if ( fields->value == ft_frame_bytes )
771           {
772             p = (FT_Byte*)structure + fields->offset;
773             FT_MEM_COPY( p, cursor, len );
774           }
775           cursor += len;
776           fields++;
777           continue;
778         }
779
780       case ft_frame_byte:
781       case ft_frame_schar:  /* read a single byte */
782         value = FT_NEXT_BYTE( cursor );
783         sign_shift = 24;
784         break;
785
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 );
789         sign_shift = 16;
790         break;
791
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 );
795         sign_shift = 16;
796         break;
797
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 );
801         sign_shift = 0;
802         break;
803
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 );
807         sign_shift = 0;
808         break;
809
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 );
813         sign_shift = 8;
814         break;
815
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 );
819         sign_shift = 8;
820         break;
821
822       default:
823         /* otherwise, exit the loop */
824         stream->cursor = cursor;
825         goto Exit;
826       }
827
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 );
831
832       /* finally, store the value in the object */
833
834       p = (FT_Byte*)structure + fields->offset;
835       switch ( fields->size )
836       {
837       case ( 8 / FT_CHAR_BIT ):
838         *(FT_Byte*)p = (FT_Byte)value;
839         break;
840
841       case ( 16 / FT_CHAR_BIT ):
842         *(FT_UShort*)p = (FT_UShort)value;
843         break;
844
845       case ( 32 / FT_CHAR_BIT ):
846         *(FT_UInt32*)p = (FT_UInt32)value;
847         break;
848
849       default:  /* for 64-bit systems */
850         *(FT_ULong*)p = (FT_ULong)value;
851       }
852
853       /* go to next field */
854       fields++;
855     }
856     while ( 1 );
857
858   Exit:
859     /* close the frame if it was opened by this read */
860     if ( frame_accessed )
861       FT_Stream_ExitFrame( stream );
862
863     return error;
864   }
865
866
867 /* END */