Lookahead: support lookahead that says to return from a state.
[gazelle.git] / runtime / bc_read_stream.c
blob40b0a07f14e209fc5464900b896ca03e6b179770
1 /*********************************************************************
3 Gazelle: a system for building fast, reusable parsers
5 bc_read_stream.c
7 This file contains routines for reading files in Bitcode format.
8 It is a stream interface -- the stream keeps only one record in
9 memory at a time, and is designed to have a very small memory
10 footprint.
12 Copyright (c) 2007 Joshua Haberman. See LICENSE for details.
14 *********************************************************************/
16 #include "bc_read_stream.h"
18 #define OP_ENCODING_FIXED 1
19 #define OP_ENCODING_VBR 2
20 #define OP_ENCODING_ARRAY 3
21 #define OP_ENCODING_CHAR6 4
23 #define ABBREV_ID_END_BLOCK 0
24 #define ABBREV_ID_ENTER_SUBBLOCK 1
25 #define ABBREV_ID_DEFINE_ABBREV 2
26 #define ABBREV_ID_UNABBREV_RECORD 3
28 #define STDBLOCK_BLOCKINFO 0
30 #define BLOCKINFO_BLOCK_SETBID 1
32 #define RESIZE_ARRAY_IF_NECESSARY(ptr, size, desired_size) \
33 if(size < desired_size) \
34 { \
35 size *= 2; \
36 ptr = realloc(ptr, size*sizeof(*ptr)); \
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
43 struct blockinfo {
44 uint32_t block_id;
45 int num_abbreviations;
46 int size_abbreviations;
47 struct blockinfo_abbrev {
48 int num_operands;
49 struct abbrev_operand *operands;
50 } *abbreviations;
53 struct stream_stack_entry
55 union {
56 struct block_metadata {
57 int abbrev_len;
58 int block_id;
59 int block_offset;
60 int block_len;
61 } block_metadata;
63 struct {
64 int first_operand_offset;
65 int num_operands;
66 } abbrev;
67 } e;
69 enum EntryType {
70 BlockMetadata,
71 Abbreviation
72 } type;
75 struct abbrev_operand
77 union {
78 long long literal_value;
79 struct {
80 unsigned char encoding;
81 int value;
82 } encoding_info;
83 } o;
85 enum OperandType {
86 Literal,
87 EncodingInfo
88 } type;
91 struct bc_read_stream
93 /* Values for the stream */
94 FILE *infile;
95 unsigned char *inmem;
96 uint32_t next_bits;
97 int num_next_bits;
98 int stream_err;
99 int stream_offset;
101 struct stream_stack_entry *old_block_metadata;
103 /* Values for the current block */
104 int abbrev_len;
105 int num_abbrevs;
106 struct stream_stack_entry *block_metadata;
107 struct blockinfo *blockinfo;
109 /* Values for the current record */
110 enum RecordType record_type;
112 /* - for data records */
113 int record_id;
114 int current_record_size;
115 int current_record_offset;
116 int record_buf_size;
117 uint64_t *record_buf;
119 /* - for StartBlock records */
120 int block_id;
121 int block_len;
123 /* - for DefineAbbrev records */
124 int record_size_abbrev;
125 int record_num_abbrev;
126 struct abbrev_operand *record_abbrev_operands;
129 /* The stream stack */
130 int stream_stack_size;
131 int stream_stack_len;
132 struct stream_stack_entry *stream_stack;
134 int abbrev_operands_size;
135 int abbrev_operands_len;
136 struct abbrev_operand *abbrev_operands;
138 /* Data about blockinfo records we have encountered */
139 int blockinfo_size;
140 int blockinfo_len;
141 struct blockinfo *blockinfos;
145 void print_abbrev(struct abbrev_operand *operands, int num_operands)
147 printf("Abbrev: num_operands=%d\n", num_operands);
148 for(int i = 0; i < num_operands; i++)
150 struct abbrev_operand *o = &operands[i];
151 if(o->type == Literal)
153 printf(" Literal value: %llu\n", o->o.literal_value);
155 else if(o->type == EncodingInfo)
157 printf(" EncodingInfo: encoding=%u, value=%d\n", o->o.encoding_info.encoding,
158 o->o.encoding_info.value);
163 void dump_stack(struct bc_read_stream *s)
165 printf("Stream stack: %d entries\n", s->stream_stack_len);
166 for(int i = 0; i < s->stream_stack_len; i++)
168 printf("- ");
169 struct stream_stack_entry *e = &s->stream_stack[i];
170 if(e->type == Abbreviation)
172 print_abbrev(s->abbrev_operands + e->e.abbrev.first_operand_offset, e->e.abbrev.num_operands);
174 else if(e->type == BlockMetadata)
176 printf("BlockMetadata: abbrev_len=%d, block_id=%d\n", e->e.block_metadata.abbrev_len,
177 e->e.block_metadata.block_id);
182 void dump_blockinfo(struct blockinfo *bi)
184 if(bi)
186 printf("Blockinfo! BlockID: %u, Abbrevs:\n", bi->block_id);
187 for(int i = 0; i < bi->num_abbreviations; i++)
188 print_abbrev(bi->abbreviations[i].operands, bi->abbreviations[i].num_operands);
193 static int refill_next_bits(struct bc_read_stream *stream);
194 struct bc_read_stream *bc_read_stream_init();
196 struct bc_read_stream *bc_rs_open_mem(const char *data)
198 struct bc_read_stream *stream = bc_read_stream_init();
199 stream->inmem = (unsigned char *)data;
200 refill_next_bits(stream);
201 return stream;
204 struct bc_read_stream *bc_rs_open_file(const char *filename)
206 FILE *infile = fopen(filename, "r");
208 if(infile == NULL)
210 return NULL;
213 char magic[4];
214 int ret = fread(magic, 4, 1, infile);
215 if(ret < 1 || magic[0] != 'B' || magic[1] != 'C')
217 fclose(infile);
218 return NULL;
221 struct bc_read_stream *stream = bc_read_stream_init();
222 stream->infile = infile;
223 refill_next_bits(stream);
224 return stream;
227 struct bc_read_stream *bc_read_stream_init()
229 /* TODO: give the application a way to get the app-specific magic number */
231 struct bc_read_stream *stream = malloc(sizeof(*stream));
232 stream->infile = NULL;
233 stream->stream_err = 0;
235 stream->next_bits = 0;
236 stream->num_next_bits = 0;
237 stream->stream_offset = 0;
239 stream->abbrev_len = 2; /* its initial value according to the spec */
240 stream->num_abbrevs = 0;
242 stream->stream_stack_size = 8; /* enough for a few levels of nesting and a few abbrevs */
243 stream->stream_stack = malloc(stream->stream_stack_size*sizeof(*stream->stream_stack));
245 /* we create an outermose stack frame -- this exists mostly to store
246 * the abbrev length of the outermost scope, and to store a bogus
247 * block_id so that we'll never find a blockinfo for the outer scope */
248 stream->stream_stack_len = 1;
249 stream->block_metadata = &stream->stream_stack[0];
250 stream->block_metadata->type = BlockMetadata;
251 stream->block_metadata->e.block_metadata.abbrev_len = stream->abbrev_len;
252 stream->block_metadata->e.block_metadata.block_id = -1;
254 stream->record_type = DataRecord; /* anything besides Eof */
256 stream->abbrev_operands_size = 8;
257 stream->abbrev_operands_len = 0;
258 stream->abbrev_operands = malloc(stream->abbrev_operands_size*sizeof(*stream->abbrev_operands));
260 stream->blockinfo_size = 8;
261 stream->blockinfo_len = 0;
262 stream->blockinfos = malloc(stream->blockinfo_size*sizeof(*stream->blockinfos));
264 stream->record_buf_size = 8;
265 stream->record_buf = malloc(stream->record_buf_size*sizeof(*stream->record_buf));
267 stream->record_size_abbrev = 8;
268 stream->record_abbrev_operands = malloc(stream->record_size_abbrev*sizeof(*stream->record_abbrev_operands));
270 return stream;
273 void bc_rs_close_stream(struct bc_read_stream *stream)
275 free(stream->record_abbrev_operands);
276 free(stream->record_buf);
277 free(stream->abbrev_operands);
278 free(stream->stream_stack);
280 for(int i = 0; i < stream->blockinfo_len; i++)
282 for(int j = 0; j < stream->blockinfos[i].num_abbreviations; j++)
284 free(stream->blockinfos[i].abbreviations[j].operands);
286 free(stream->blockinfos[i].abbreviations);
288 free(stream->blockinfos);
290 if(stream->infile)
291 fclose(stream->infile);
292 free(stream);
295 uint64_t bc_rs_read_64(struct bc_read_stream *stream, int i)
297 if(i > stream->current_record_size)
299 stream->stream_err |= BITCODE_ERR_NO_SUCH_VALUE;
300 return 0;
302 else
304 return stream->record_buf[i];
309 #define GETTER_FUNC(type, bits) \
310 type bc_rs_read_ ## bits (struct bc_read_stream *stream, int i) \
312 uint64_t val = bc_rs_read_64(stream, i); \
313 if(stream->record_buf[i] > ((1ULL << bits) - 1)) \
315 stream->stream_err |= BITCODE_ERR_VALUE_TOO_LARGE; \
316 return 0; \
318 else \
320 return (type)val; \
324 GETTER_FUNC(uint8_t, 8)
325 GETTER_FUNC(uint16_t, 16)
326 GETTER_FUNC(uint32_t, 32)
328 #define NEXT_GETTER_FUNC(type, bits) \
329 type bc_rs_read_next_ ## bits (struct bc_read_stream *stream) \
331 return bc_rs_read_ ## bits(stream, stream->current_record_offset++); \
334 NEXT_GETTER_FUNC(uint8_t, 8)
335 NEXT_GETTER_FUNC(uint16_t, 16)
336 NEXT_GETTER_FUNC(uint32_t, 32)
337 NEXT_GETTER_FUNC(uint64_t, 64)
339 static int refill_next_bits(struct bc_read_stream *stream)
341 unsigned char buf[4];
343 stream->stream_offset += 4;
345 if(stream->infile)
347 int ret = fread(buf, 4, 1, stream->infile);
348 if(ret < 1)
350 //if(feof(stream->infile))
351 // stream->record_type = Eof;
353 if(ferror(stream->infile))
354 stream->stream_err |= BITCODE_ERR_IO;
356 return -1;
359 else
361 memcpy(buf, stream->inmem + stream->stream_offset, 4);
364 stream->next_bits = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
365 stream->num_next_bits = 32;
367 return 0;
370 #define LOW_BITS(bitfield, num_bits) (bitfield & (~0U >> (32-num_bits)))
372 static uint32_t read_fixed(struct bc_read_stream *stream, int num_bits)
374 uint32_t ret;
376 if(stream->num_next_bits >= num_bits)
378 /* next_bits already contains all the bits we need -- take them */
379 ret = LOW_BITS(stream->next_bits, num_bits);
380 stream->next_bits >>= num_bits;
381 stream->num_next_bits -= num_bits;
383 else
385 /* we need all of next_bits, and then some */
386 ret = stream->next_bits;
387 int bits_filled = stream->num_next_bits;
388 int bits_left = num_bits - bits_filled;
390 if(refill_next_bits(stream) < 0) return 0;
392 /* take bits_left bits from the next_bits */
393 ret |= LOW_BITS(stream->next_bits, bits_left) << bits_filled;
395 if(bits_left != 32)
396 stream->next_bits >>= bits_left;
397 else
398 stream->next_bits = 0;
400 stream->num_next_bits -= bits_left;
403 if(stream->num_next_bits == 0)
405 /* We could defer this, but doing it now makes our stream_offset more accurate */
406 refill_next_bits(stream);
409 return ret;
412 static uint64_t read_fixed_64(struct bc_read_stream *stream, int num_bits)
414 if(num_bits <= 32)
416 return read_fixed(stream, num_bits);
418 else
420 uint64_t ret = read_fixed(stream, 32);
421 return ret | ((uint64_t)read_fixed(stream, num_bits-32) << 32);
425 static uint64_t read_vbr_64(struct bc_read_stream *stream, int bits)
427 uint64_t val = 0;
428 int read_bits = 0;
429 int continuation_bit = 1 << (bits-1);
430 int value_bits = continuation_bit - 1;
431 int continues = 0;
433 do {
434 uint32_t next_bits = read_fixed(stream, bits);
435 continues = next_bits & continuation_bit;
436 val |= (next_bits & value_bits) << read_bits;
437 read_bits += bits-1;
438 } while(continues);
440 return val;
443 static uint32_t read_vbr(struct bc_read_stream *stream, int bits)
445 uint64_t val = read_vbr_64(stream, bits);
446 if(val >> 32)
448 stream->stream_err |= BITCODE_ERR_CORRUPT_INPUT;
449 return 0;
451 else
453 return (uint32_t)val;
457 static uint8_t decode_char6(int num)
459 if(num < 26) return 'a' + num;
460 else if(num < 52) return 'A' + (num-26);
461 else if(num < 62) return '0' + (num-52);
462 else if(num < 63) return '.';
463 else return '_';
466 /* This can handle any abbreviated type except for arrays */
467 static uint64_t read_abbrev_value(struct bc_read_stream *stream, struct abbrev_operand *op)
469 if(op->type == Literal)
470 return op->o.literal_value;
471 else
473 switch(op->o.encoding_info.encoding) {
474 case OP_ENCODING_FIXED:
475 return read_fixed_64(stream, op->o.encoding_info.value);
476 case OP_ENCODING_VBR:
477 return read_vbr_64(stream, op->o.encoding_info.value);
478 case OP_ENCODING_CHAR6:
479 return decode_char6(read_fixed(stream, 6));
480 default:
481 stream->stream_err |= BITCODE_ERR_INTERNAL;
482 return 0;
487 static void append_value(struct bc_read_stream *stream, uint64_t val)
489 RESIZE_ARRAY_IF_NECESSARY(stream->record_buf, stream->record_buf_size, stream->current_record_size+1);
490 stream->record_buf[stream->current_record_size++] = val;
493 static void read_user_abbreviated_record(struct bc_read_stream *stream,
494 struct abbrev_operand *ops,
495 int num_operands)
497 stream->current_record_size = 0;
499 for(int i = 0; i < num_operands; i++)
501 struct abbrev_operand *op = &ops[i];
503 if(op->type == EncodingInfo && op->o.encoding_info.encoding == OP_ENCODING_ARRAY)
505 int num_elements = read_vbr(stream, 6);
506 i += 1;
507 for(int j = 0; j < num_elements; j++)
508 append_value(stream, read_abbrev_value(stream, &ops[i]));
510 else
512 uint64_t val = read_abbrev_value(stream, &ops[i]);
513 if(i == 0)
515 stream->record_id = val;
517 else
519 append_value(stream, val);
525 static int read_abbrev_op(struct bc_read_stream *stream, struct abbrev_operand *o, int array_ok)
527 int is_literal = read_fixed(stream, 1);
528 if(is_literal)
530 o->type = Literal;
531 o->o.literal_value = read_vbr(stream, 8);
533 else
535 o->type = EncodingInfo;
536 o->o.encoding_info.encoding = read_fixed(stream, 3);
537 switch(o->o.encoding_info.encoding)
539 case OP_ENCODING_FIXED:
540 case OP_ENCODING_VBR:
541 o->o.encoding_info.value = read_vbr(stream, 5);
542 break;
544 case OP_ENCODING_ARRAY:
545 if(!array_ok) return -1;
546 break;
548 case OP_ENCODING_CHAR6:
549 break;
552 return 0;
556 void align_32_bits(struct bc_read_stream *stream)
558 if(stream->num_next_bits != 32)
559 refill_next_bits(stream);
562 struct blockinfo *find_blockinfo(struct bc_read_stream *stream, int block_id)
564 for(int i = 0; i < stream->blockinfo_len; i++)
565 if(stream->blockinfos[i].block_id == block_id)
566 return &stream->blockinfos[i];
568 return NULL;
571 struct blockinfo *find_or_create_blockinfo(struct bc_read_stream *stream, int block_id)
573 struct blockinfo *bi = find_blockinfo(stream, block_id);
575 if(bi)
577 return bi;
579 else
581 RESIZE_ARRAY_IF_NECESSARY(stream->blockinfos, stream->blockinfo_size, stream->blockinfo_len+1);
583 struct blockinfo *new_bi = &stream->blockinfos[stream->blockinfo_len++];
585 new_bi->block_id = block_id;
586 new_bi->num_abbreviations = 0;
587 new_bi->size_abbreviations = 8;
588 new_bi->abbreviations = malloc(new_bi->size_abbreviations * sizeof(*new_bi->abbreviations));
590 return new_bi;
594 static void pop_stack_frame(struct bc_read_stream *stream)
596 stream->stream_stack_len = stream->block_metadata - stream->stream_stack;
597 if(stream->stream_stack_len == 0)
599 stream->record_type = Eof;
600 return;
603 stream->num_abbrevs = 0;
604 stream->block_metadata--;
605 while(stream->block_metadata->type == Abbreviation)
607 stream->num_abbrevs++;
608 stream->block_metadata--;
611 stream->abbrev_len = stream->block_metadata->e.block_metadata.abbrev_len;
612 stream->block_id = stream->block_metadata->e.block_metadata.block_id;
613 stream->blockinfo = find_blockinfo(stream, stream->block_id);
617 void bc_rs_next_record(struct bc_read_stream *stream)
619 /* don't attempt to read past eof */
620 if(stream->record_type == Eof) return;
622 int abbrev_id = read_fixed(stream, stream->abbrev_len);
623 stream->current_record_offset = 0;
625 switch(abbrev_id) {
626 case ABBREV_ID_END_BLOCK:
627 stream->record_type = EndBlock;
628 stream->old_block_metadata = stream->block_metadata;
630 align_32_bits(stream);
631 pop_stack_frame(stream);
633 break;
635 case ABBREV_ID_ENTER_SUBBLOCK:
636 stream->block_id = read_vbr(stream, 8);
637 stream->abbrev_len = read_vbr(stream, 4);
638 align_32_bits(stream);
639 stream->block_len = read_fixed(stream, 32);
640 stream->record_type = StartBlock;
642 RESIZE_ARRAY_IF_NECESSARY(stream->stream_stack, stream->stream_stack_size,
643 stream->stream_stack_len+1);
645 stream->block_metadata = &stream->stream_stack[stream->stream_stack_len++];
646 stream->block_metadata->type = BlockMetadata;
647 stream->block_metadata->e.block_metadata.block_id = stream->block_id;
648 stream->block_metadata->e.block_metadata.abbrev_len = stream->abbrev_len;
649 stream->block_metadata->e.block_metadata.block_offset = stream->stream_offset;
650 stream->block_metadata->e.block_metadata.block_len = stream->block_len;
652 //printf("++ Entering block id=%d, offset=%d\n", stream->block_id, stream->stream_offset);
654 stream->blockinfo = find_or_create_blockinfo(stream, stream->block_id);
655 break;
657 case ABBREV_ID_DEFINE_ABBREV:
658 stream->record_type = DefineAbbrev;
659 stream->record_num_abbrev = read_vbr(stream, 5);
661 RESIZE_ARRAY_IF_NECESSARY(stream->record_abbrev_operands, stream->record_size_abbrev,
662 stream->record_num_abbrev);
664 for(int i = 0; i < stream->record_num_abbrev; i++)
666 read_abbrev_op(stream, &stream->record_abbrev_operands[i], 0);
669 break;
671 case ABBREV_ID_UNABBREV_RECORD:
672 stream->record_type = DataRecord;
673 stream->record_id = read_vbr(stream, 6);
675 stream->current_record_size = read_vbr(stream, 6);
677 RESIZE_ARRAY_IF_NECESSARY(stream->record_buf, stream->record_buf_size,
678 stream->current_record_size+1);
680 for(int i = 0; i < stream->current_record_size; i++)
681 stream->record_buf[i] = read_vbr(stream, 6);
682 break;
684 default:
686 /* This must be a user-defined abbreviation. It could come from the
687 * blockinfo-defined abbreviations or abbreviations defined in this
688 * block. */
689 stream->record_type = DataRecord;
690 int user_abbrev_id = abbrev_id - 4;
691 int num_blockinfo_abbrevs = stream->blockinfo ? stream->blockinfo->num_abbreviations : 0;
692 int block_abbrev_id = user_abbrev_id - num_blockinfo_abbrevs;
693 if(user_abbrev_id < num_blockinfo_abbrevs)
695 struct blockinfo_abbrev *a = &stream->blockinfo->abbreviations[user_abbrev_id];
696 read_user_abbreviated_record(stream, a->operands, a->num_operands);
698 else if(block_abbrev_id < stream->num_abbrevs)
700 struct stream_stack_entry *e = stream->block_metadata + block_abbrev_id + 1;
701 struct abbrev_operand *o = stream->abbrev_operands + e->e.abbrev.first_operand_offset;
702 read_user_abbreviated_record(stream, o, e->e.abbrev.num_operands);
704 else
706 stream->stream_err |= BITCODE_ERR_CORRUPT_INPUT;
708 break;
713 struct record_info bc_rs_next_data_record(struct bc_read_stream *stream)
715 while(1)
717 bc_rs_next_record(stream);
719 if(stream->record_type == DefineAbbrev)
721 int num_ops = stream->record_num_abbrev;
723 RESIZE_ARRAY_IF_NECESSARY(stream->stream_stack, stream->stream_stack_size,
724 stream->stream_stack_len+1);
725 RESIZE_ARRAY_IF_NECESSARY(stream->abbrev_operands, stream->abbrev_operands_size,
726 stream->abbrev_operands_len+num_ops+1);
728 struct stream_stack_entry *e = &stream->stream_stack[stream->stream_stack_len++];
729 e->type = Abbreviation;
730 e->e.abbrev.first_operand_offset = stream->abbrev_operands_len;
731 e->e.abbrev.num_operands = num_ops;
732 struct abbrev_operand *abbrev_operands = &stream->abbrev_operands[stream->abbrev_operands_len];
733 stream->abbrev_operands_len += num_ops;
735 for(int i = 0; i < num_ops; i++)
736 abbrev_operands[i] = stream->record_abbrev_operands[i];
738 stream->num_abbrevs++;
740 else if(stream->record_type == StartBlock && stream->block_id == STDBLOCK_BLOCKINFO)
742 /* The first record must be a SETBID record */
743 bc_rs_next_record(stream);
744 struct blockinfo *bi = NULL;
746 while(1)
748 if(stream->record_type == EndBlock)
750 break;
752 else if(stream->record_type == Err || stream->record_type == Eof)
754 struct record_info ri;
755 ri.record_type = stream->record_type;
756 ri.id = 0;
757 return ri;
759 else if(stream->record_type == DataRecord)
761 if(stream->record_id == BLOCKINFO_BLOCK_SETBID)
763 if(stream->current_record_size != 1)
765 /* TODO */
766 stream->stream_err |= BITCODE_ERR_CORRUPT_INPUT;
768 bi = find_or_create_blockinfo(stream, stream->record_buf[0]);
771 else if(stream->record_type == DefineAbbrev)
774 if(bi == NULL)
776 /* TODO */
777 stream->stream_err |= BITCODE_ERR_CORRUPT_INPUT;
780 RESIZE_ARRAY_IF_NECESSARY(bi->abbreviations,
781 bi->size_abbreviations, bi->num_abbreviations+1);
783 struct blockinfo_abbrev *abbrev = &bi->abbreviations[bi->num_abbreviations++];
784 abbrev->num_operands = stream->record_num_abbrev;
785 abbrev->operands = malloc(sizeof(*abbrev->operands) * abbrev->num_operands);
786 for(int i = 0; i < abbrev->num_operands; i++)
787 abbrev->operands[i] = stream->record_abbrev_operands[i];
790 bc_rs_next_record(stream);
794 else
796 struct record_info ri;
797 ri.record_type = stream->record_type;
798 ri.id = 0;
800 if(ri.record_type == StartBlock) ri.id = stream->block_id;
801 else if(ri.record_type == DataRecord) ri.id = stream->record_id;
803 return ri;
808 int bc_rs_get_error(struct bc_read_stream *stream)
810 return stream->stream_err;
813 int bc_rs_get_record_size(struct bc_read_stream *stream)
815 return stream->current_record_size;
818 int bc_rs_get_remaining_record_size(struct bc_read_stream *stream)
820 return stream->current_record_size - stream->current_record_offset;
823 void bc_rs_skip_block(struct bc_read_stream *stream)
825 int offset = stream->block_metadata->e.block_metadata.block_offset +
826 (stream->block_metadata->e.block_metadata.block_len * 4);
828 if(stream->infile)
829 fseek(stream->infile, offset, SEEK_SET);
831 stream->stream_offset = offset-4;
832 refill_next_bits(stream);
833 pop_stack_frame(stream);
836 void bc_rs_rewind_block(struct bc_read_stream *stream)
838 if(stream->record_type == EndBlock)
840 stream->num_abbrevs = stream->old_block_metadata - stream->block_metadata - 1;
841 stream->block_metadata = stream->old_block_metadata;
842 stream->abbrev_len = stream->block_metadata->e.block_metadata.abbrev_len;
843 stream->block_id = stream->block_metadata->e.block_metadata.block_id;
844 stream->blockinfo = find_or_create_blockinfo(stream, stream->block_id);
845 stream->stream_stack_len = stream->block_metadata - stream->stream_stack + 1;
848 int offset = stream->block_metadata->e.block_metadata.block_offset;
850 if(stream->infile)
851 fseek(stream->infile, offset, SEEK_SET);
853 stream->stream_offset = offset-4;
854 refill_next_bits(stream);
855 align_32_bits(stream);
859 * Local Variables:
860 * c-file-style: "bsd"
861 * c-basic-offset: 4
862 * indent-tabs-mode: nil
863 * End:
864 * vim:et:sts=4:sw=4