diff options
Diffstat (limited to 'src/video-support/AVIChunk.vala')
-rw-r--r-- | src/video-support/AVIChunk.vala | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/video-support/AVIChunk.vala b/src/video-support/AVIChunk.vala new file mode 100644 index 0000000..970f443 --- /dev/null +++ b/src/video-support/AVIChunk.vala @@ -0,0 +1,121 @@ +private class AVIChunk { + private GLib.File file = null; + private string section_name = ""; + private uint64 section_size = 0; + private uint64 section_offset = 0; + private GLib.DataInputStream input = null; + private AVIChunk? parent = null; + private const int MAX_STRING_TO_SECTION_LENGTH = 1024; + + public AVIChunk(GLib.File file) { + this.file = file; + } + + private AVIChunk.with_input_stream(GLib.DataInputStream input, AVIChunk parent) { + this.input = input; + this.parent = parent; + } + + public void open_file() throws GLib.Error { + close_file(); + input = new GLib.DataInputStream(file.read()); + input.set_byte_order(DataStreamByteOrder.LITTLE_ENDIAN); + section_size = 0; + section_offset = 0; + section_name = ""; + } + + public void close_file() throws GLib.Error { + if (null != input) { + input.close(); + input = null; + } + } + + public void nonsection_skip(uint64 skip_amount) throws GLib.Error { + skip_uint64(input, skip_amount); + } + + public void skip(uint64 skip_amount) throws GLib.Error { + advance_section_offset(skip_amount); + skip_uint64(input, skip_amount); + } + + public AVIChunk get_first_child_chunk() { + return new AVIChunk.with_input_stream(input, this); + } + + private void advance_section_offset(uint64 amount) { + if ((section_offset + amount) > section_size) + amount = section_size - section_offset; + + section_offset += amount; + if (null != parent) { + parent.advance_section_offset(amount); + } + } + + public uchar read_byte() throws GLib.Error { + advance_section_offset(1); + return input.read_byte(); + } + + public uint16 read_uint16() throws GLib.Error { + advance_section_offset(2); + return input.read_uint16(); + } + + public void read_chunk() throws GLib.Error { + // don't use checked reads here because they advance the section offset, which we're trying + // to determine here + GLib.StringBuilder sb = new GLib.StringBuilder(); + sb.append_c((char) input.read_byte()); + sb.append_c((char) input.read_byte()); + sb.append_c((char) input.read_byte()); + sb.append_c((char) input.read_byte()); + section_name = sb.str; + section_size = input.read_uint32(); + section_offset = 0; + } + + public string read_name() throws GLib.Error { + GLib.StringBuilder sb = new GLib.StringBuilder(); + sb.append_c((char) read_byte()); + sb.append_c((char) read_byte()); + sb.append_c((char) read_byte()); + sb.append_c((char) read_byte()); + return sb.str; + } + + public void next_chunk() throws GLib.Error { + skip(section_size_remaining()); + section_size = 0; + section_offset = 0; + } + + public string get_current_chunk_name() { + return section_name; + } + + public bool is_last_chunk() { + return section_size == 0; + } + + public uint64 section_size_remaining() { + assert(section_size >= section_offset); + return section_size - section_offset; + } + + // Reads section contents into a string. + public string section_to_string() throws GLib.Error { + GLib.StringBuilder sb = new GLib.StringBuilder(); + while (section_offset < section_size) { + sb.append_c((char) read_byte()); + if (sb.len > MAX_STRING_TO_SECTION_LENGTH) { + return sb.str; + } + } + return sb.str; + } + +} |