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