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