This commit was manufactured by cvs2svn to create branch 'captive'.
[reactos.git] / lib / freetype / src / base / ftstream.c
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 )
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 )
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 )
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 )
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 )
100   FT_Stream_Pos( FT_Stream  stream )
101   {
102     return stream->pos;
103   }
104
105
106   FT_BASE_DEF( FT_Error )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 */