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