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