Sync with trunk (r48144)
[reactos.git] / lib / 3rdparty / freetype / src / base / ftstream.c
1 /***************************************************************************/
2 /* */
3 /* ftstream.c */
4 /* */
5 /* I/O stream support (body). */
6 /* */
7 /* Copyright 2000-2001, 2002, 2004, 2005, 2006, 2008, 2009 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 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_Err_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_Err_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_Err_Invalid_Stream_Operation;
97
98 return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) );
99 }
100
101
102 FT_BASE_DEF( FT_Long )
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_Err_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_Err_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 = 0;
207 stream->limit = 0;
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 #ifdef FT_DEBUG_MEMORY
223 ft_mem_free( memory, *pbytes );
224 *pbytes = NULL;
225 #else
226 FT_FREE( *pbytes );
227 #endif
228 }
229 *pbytes = 0;
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 /* check for nested frame access */
242 FT_ASSERT( stream && stream->cursor == 0 );
243
244 if ( stream->read )
245 {
246 /* allocate the frame in memory */
247 FT_Memory memory = stream->memory;
248
249 #ifdef FT_DEBUG_MEMORY
250 /* assume _ft_debug_file and _ft_debug_lineno are already set */
251 stream->base = (unsigned char*)ft_mem_qalloc( memory, count, &error );
252 if ( error )
253 goto Exit;
254 #else
255 if ( FT_QALLOC( stream->base, count ) )
256 goto Exit;
257 #endif
258 /* read it */
259 read_bytes = stream->read( stream, stream->pos,
260 stream->base, count );
261 if ( read_bytes < count )
262 {
263 FT_ERROR(( "FT_Stream_EnterFrame:"
264 " invalid read; expected %lu bytes, got %lu\n",
265 count, read_bytes ));
266
267 FT_FREE( stream->base );
268 error = FT_Err_Invalid_Stream_Operation;
269 }
270 stream->cursor = stream->base;
271 stream->limit = stream->cursor + count;
272 stream->pos += read_bytes;
273 }
274 else
275 {
276 /* check current and new position */
277 if ( stream->pos >= stream->size ||
278 stream->pos + count > stream->size )
279 {
280 FT_ERROR(( "FT_Stream_EnterFrame:"
281 " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
282 stream->pos, count, stream->size ));
283
284 error = FT_Err_Invalid_Stream_Operation;
285 goto Exit;
286 }
287
288 /* set cursor */
289 stream->cursor = stream->base + stream->pos;
290 stream->limit = stream->cursor + count;
291 stream->pos += count;
292 }
293
294 Exit:
295 return error;
296 }
297
298
299 FT_BASE_DEF( void )
300 FT_Stream_ExitFrame( FT_Stream stream )
301 {
302 /* IMPORTANT: The assertion stream->cursor != 0 was removed, given */
303 /* that it is possible to access a frame of length 0 in */
304 /* some weird fonts (usually, when accessing an array of */
305 /* 0 records, like in some strange kern tables). */
306 /* */
307 /* In this case, the loader code handles the 0-length table */
308 /* gracefully; however, stream.cursor is really set to 0 by the */
309 /* FT_Stream_EnterFrame() call, and this is not an error. */
310 /* */
311 FT_ASSERT( stream );
312
313 if ( stream->read )
314 {
315 FT_Memory memory = stream->memory;
316
317 #ifdef FT_DEBUG_MEMORY
318 ft_mem_free( memory, stream->base );
319 stream->base = NULL;
320 #else
321 FT_FREE( stream->base );
322 #endif
323 }
324 stream->cursor = 0;
325 stream->limit = 0;
326 }
327
328
329 FT_BASE_DEF( FT_Char )
330 FT_Stream_GetChar( FT_Stream stream )
331 {
332 FT_Char result;
333
334
335 FT_ASSERT( stream && stream->cursor );
336
337 result = 0;
338 if ( stream->cursor < stream->limit )
339 result = *stream->cursor++;
340
341 return result;
342 }
343
344
345 FT_BASE_DEF( FT_Short )
346 FT_Stream_GetShort( FT_Stream stream )
347 {
348 FT_Byte* p;
349 FT_Short result;
350
351
352 FT_ASSERT( stream && stream->cursor );
353
354 result = 0;
355 p = stream->cursor;
356 if ( p + 1 < stream->limit )
357 result = FT_NEXT_SHORT( p );
358 stream->cursor = p;
359
360 return result;
361 }
362
363
364 FT_BASE_DEF( FT_Short )
365 FT_Stream_GetShortLE( FT_Stream stream )
366 {
367 FT_Byte* p;
368 FT_Short result;
369
370
371 FT_ASSERT( stream && stream->cursor );
372
373 result = 0;
374 p = stream->cursor;
375 if ( p + 1 < stream->limit )
376 result = FT_NEXT_SHORT_LE( p );
377 stream->cursor = p;
378
379 return result;
380 }
381
382
383 FT_BASE_DEF( FT_Long )
384 FT_Stream_GetOffset( FT_Stream stream )
385 {
386 FT_Byte* p;
387 FT_Long result;
388
389
390 FT_ASSERT( stream && stream->cursor );
391
392 result = 0;
393 p = stream->cursor;
394 if ( p + 2 < stream->limit )
395 result = FT_NEXT_OFF3( p );
396 stream->cursor = p;
397 return result;
398 }
399
400
401 FT_BASE_DEF( FT_Long )
402 FT_Stream_GetLong( FT_Stream stream )
403 {
404 FT_Byte* p;
405 FT_Long result;
406
407
408 FT_ASSERT( stream && stream->cursor );
409
410 result = 0;
411 p = stream->cursor;
412 if ( p + 3 < stream->limit )
413 result = FT_NEXT_LONG( p );
414 stream->cursor = p;
415 return result;
416 }
417
418
419 FT_BASE_DEF( FT_Long )
420 FT_Stream_GetLongLE( FT_Stream stream )
421 {
422 FT_Byte* p;
423 FT_Long result;
424
425
426 FT_ASSERT( stream && stream->cursor );
427
428 result = 0;
429 p = stream->cursor;
430 if ( p + 3 < stream->limit )
431 result = FT_NEXT_LONG_LE( p );
432 stream->cursor = p;
433 return result;
434 }
435
436
437 FT_BASE_DEF( FT_Char )
438 FT_Stream_ReadChar( FT_Stream stream,
439 FT_Error* error )
440 {
441 FT_Byte result = 0;
442
443
444 FT_ASSERT( stream );
445
446 *error = FT_Err_Ok;
447
448 if ( stream->read )
449 {
450 if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
451 goto Fail;
452 }
453 else
454 {
455 if ( stream->pos < stream->size )
456 result = stream->base[stream->pos];
457 else
458 goto Fail;
459 }
460 stream->pos++;
461
462 return result;
463
464 Fail:
465 *error = FT_Err_Invalid_Stream_Operation;
466 FT_ERROR(( "FT_Stream_ReadChar:"
467 " 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_ReadShort( 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( 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_ReadShort:"
514 " 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_Short )
522 FT_Stream_ReadShortLE( FT_Stream stream,
523 FT_Error* error )
524 {
525 FT_Byte reads[2];
526 FT_Byte* p = 0;
527 FT_Short result = 0;
528
529
530 FT_ASSERT( stream );
531
532 *error = FT_Err_Ok;
533
534 if ( stream->pos + 1 < stream->size )
535 {
536 if ( stream->read )
537 {
538 if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
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_SHORT_LE( p );
550 }
551 else
552 goto Fail;
553
554 stream->pos += 2;
555
556 return result;
557
558 Fail:
559 *error = FT_Err_Invalid_Stream_Operation;
560 FT_ERROR(( "FT_Stream_ReadShortLE:"
561 " 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_ReadOffset( FT_Stream stream,
570 FT_Error* error )
571 {
572 FT_Byte reads[3];
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 + 2 < stream->size )
582 {
583 if ( stream->read )
584 {
585 if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
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_OFF3( p );
597 }
598 else
599 goto Fail;
600
601 stream->pos += 3;
602
603 return result;
604
605 Fail:
606 *error = FT_Err_Invalid_Stream_Operation;
607 FT_ERROR(( "FT_Stream_ReadOffset:"
608 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
609 stream->pos, stream->size ));
610
611 return 0;
612 }
613
614
615 FT_BASE_DEF( FT_Long )
616 FT_Stream_ReadLong( FT_Stream stream,
617 FT_Error* error )
618 {
619 FT_Byte reads[4];
620 FT_Byte* p = 0;
621 FT_Long result = 0;
622
623
624 FT_ASSERT( stream );
625
626 *error = FT_Err_Ok;
627
628 if ( stream->pos + 3 < stream->size )
629 {
630 if ( stream->read )
631 {
632 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
633 goto Fail;
634
635 p = reads;
636 }
637 else
638 {
639 p = stream->base + stream->pos;
640 }
641
642 if ( p )
643 result = FT_NEXT_LONG( p );
644 }
645 else
646 goto Fail;
647
648 stream->pos += 4;
649
650 return result;
651
652 Fail:
653 *error = FT_Err_Invalid_Stream_Operation;
654 FT_ERROR(( "FT_Stream_ReadLong:"
655 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
656 stream->pos, stream->size ));
657
658 return 0;
659 }
660
661
662 FT_BASE_DEF( FT_Long )
663 FT_Stream_ReadLongLE( FT_Stream stream,
664 FT_Error* error )
665 {
666 FT_Byte reads[4];
667 FT_Byte* p = 0;
668 FT_Long result = 0;
669
670
671 FT_ASSERT( stream );
672
673 *error = FT_Err_Ok;
674
675 if ( stream->pos + 3 < stream->size )
676 {
677 if ( stream->read )
678 {
679 if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
680 goto Fail;
681
682 p = reads;
683 }
684 else
685 {
686 p = stream->base + stream->pos;
687 }
688
689 if ( p )
690 result = FT_NEXT_LONG_LE( p );
691 }
692 else
693 goto Fail;
694
695 stream->pos += 4;
696
697 return result;
698
699 Fail:
700 *error = FT_Err_Invalid_Stream_Operation;
701 FT_ERROR(( "FT_Stream_ReadLongLE:"
702 " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
703 stream->pos, stream->size ));
704
705 return 0;
706 }
707
708
709 FT_BASE_DEF( FT_Error )
710 FT_Stream_ReadFields( FT_Stream stream,
711 const FT_Frame_Field* fields,
712 void* structure )
713 {
714 FT_Error error;
715 FT_Bool frame_accessed = 0;
716 FT_Byte* cursor;
717
718 if ( !fields || !stream )
719 return FT_Err_Invalid_Argument;
720
721 cursor = stream->cursor;
722
723 error = FT_Err_Ok;
724 do
725 {
726 FT_ULong value;
727 FT_Int sign_shift;
728 FT_Byte* p;
729
730
731 switch ( fields->value )
732 {
733 case ft_frame_start: /* access a new frame */
734 error = FT_Stream_EnterFrame( stream, fields->offset );
735 if ( error )
736 goto Exit;
737
738 frame_accessed = 1;
739 cursor = stream->cursor;
740 fields++;
741 continue; /* loop! */
742
743 case ft_frame_bytes: /* read a byte sequence */
744 case ft_frame_skip: /* skip some bytes */
745 {
746 FT_UInt len = fields->size;
747
748
749 if ( cursor + len > stream->limit )
750 {
751 error = FT_Err_Invalid_Stream_Operation;
752 goto Exit;
753 }
754
755 if ( fields->value == ft_frame_bytes )
756 {
757 p = (FT_Byte*)structure + fields->offset;
758 FT_MEM_COPY( p, cursor, len );
759 }
760 cursor += len;
761 fields++;
762 continue;
763 }
764
765 case ft_frame_byte:
766 case ft_frame_schar: /* read a single byte */
767 value = FT_NEXT_BYTE(cursor);
768 sign_shift = 24;
769 break;
770
771 case ft_frame_short_be:
772 case ft_frame_ushort_be: /* read a 2-byte big-endian short */
773 value = FT_NEXT_USHORT(cursor);
774 sign_shift = 16;
775 break;
776
777 case ft_frame_short_le:
778 case ft_frame_ushort_le: /* read a 2-byte little-endian short */
779 value = FT_NEXT_USHORT_LE(cursor);
780 sign_shift = 16;
781 break;
782
783 case ft_frame_long_be:
784 case ft_frame_ulong_be: /* read a 4-byte big-endian long */
785 value = FT_NEXT_ULONG(cursor);
786 sign_shift = 0;
787 break;
788
789 case ft_frame_long_le:
790 case ft_frame_ulong_le: /* read a 4-byte little-endian long */
791 value = FT_NEXT_ULONG_LE(cursor);
792 sign_shift = 0;
793 break;
794
795 case ft_frame_off3_be:
796 case ft_frame_uoff3_be: /* read a 3-byte big-endian long */
797 value = FT_NEXT_UOFF3(cursor);
798 sign_shift = 8;
799 break;
800
801 case ft_frame_off3_le:
802 case ft_frame_uoff3_le: /* read a 3-byte little-endian long */
803 value = FT_NEXT_UOFF3_LE(cursor);
804 sign_shift = 8;
805 break;
806
807 default:
808 /* otherwise, exit the loop */
809 stream->cursor = cursor;
810 goto Exit;
811 }
812
813 /* now, compute the signed value is necessary */
814 if ( fields->value & FT_FRAME_OP_SIGNED )
815 value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
816
817 /* finally, store the value in the object */
818
819 p = (FT_Byte*)structure + fields->offset;
820 switch ( fields->size )
821 {
822 case (8 / FT_CHAR_BIT):
823 *(FT_Byte*)p = (FT_Byte)value;
824 break;
825
826 case (16 / FT_CHAR_BIT):
827 *(FT_UShort*)p = (FT_UShort)value;
828 break;
829
830 case (32 / FT_CHAR_BIT):
831 *(FT_UInt32*)p = (FT_UInt32)value;
832 break;
833
834 default: /* for 64-bit systems */
835 *(FT_ULong*)p = (FT_ULong)value;
836 }
837
838 /* go to next field */
839 fields++;
840 }
841 while ( 1 );
842
843 Exit:
844 /* close the frame if it was opened by this read */
845 if ( frame_accessed )
846 FT_Stream_ExitFrame( stream );
847
848 return error;
849 }
850
851
852 /* END */