aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorPatrick Walton <[email protected]>2011-03-22 13:59:17 -0700
committerPatrick Walton <[email protected]>2011-03-22 14:00:27 -0700
commit6623597c187c025095842598f7d9db816cb1858b (patch)
treede37f502a98eae013716e5366b4331c863fe95ff /src/lib
parentAdd Tim to AUTHORS. (diff)
downloadrust-6623597c187c025095842598f7d9db816cb1858b.tar.xz
rust-6623597c187c025095842598f7d9db816cb1858b.zip
lib: Add an EBML reader module
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ebml.rs109
-rw-r--r--src/lib/std.rc1
2 files changed, 110 insertions, 0 deletions
diff --git a/src/lib/ebml.rs b/src/lib/ebml.rs
new file mode 100644
index 00000000..7b413c63
--- /dev/null
+++ b/src/lib/ebml.rs
@@ -0,0 +1,109 @@
+// Simple Extensible Binary Markup Language (EBML) reader and writer on a
+// cursor model. See the specification here:
+// http://www.matroska.org/technical/specs/rfc/index.html
+
+import option.none;
+import option.some;
+
+type ebml_tag = rec(uint id, uint size);
+type ebml_state = rec(ebml_tag ebml_tag, uint pos);
+
+// TODO: When we have module renaming, make "reader" and "writer" separate
+// modules within this file.
+
+// EBML reading
+
+type reader = rec(
+ io.reader reader,
+ mutable vec[ebml_state] states,
+ uint size
+);
+
+// TODO: eventually use u64 or big here
+impure fn read_vint(&io.reader reader) -> uint {
+ auto a = reader.read_byte();
+ if (a & 0x80u8 != 0u8) { ret (a & 0x7fu8) as uint; }
+ auto b = reader.read_byte();
+ if (a & 0x40u8 != 0u8) {
+ ret (((a & 0x3fu8) as uint) << 8u) | (b as uint);
+ }
+ auto c = reader.read_byte();
+ if (a & 0x20u8 != 0u8) {
+ ret (((a & 0x1fu8) as uint) << 16u) | ((b as uint) << 8u) |
+ (c as uint);
+ }
+ auto d = reader.read_byte();
+ if (a & 0x10u8 != 0u8) {
+ ret (((a & 0x0fu8) as uint) << 24u) | ((b as uint) << 16u) |
+ ((c as uint) << 8u) | (d as uint);
+ }
+
+ log "vint too big"; fail;
+}
+
+impure fn create_reader(&io.reader r) -> reader {
+ let vec[ebml_state] states = vec();
+
+ // Calculate the size of the stream.
+ auto pos = r.tell();
+ r.seek(0, io.seek_end);
+ auto size = r.tell() - pos;
+ r.seek(pos as int, io.seek_set);
+
+ ret rec(reader=r, mutable states=states, size=size);
+}
+
+impure fn bytes_left(&reader r) -> uint {
+ auto pos = r.reader.tell();
+ alt (_vec.last[ebml_state](r.states)) {
+ case (none[ebml_state]) { ret r.size - pos; }
+ case (some[ebml_state](?st)) { ret st.pos + st.ebml_tag.size - pos; }
+ }
+}
+
+impure fn read_tag(&reader r) -> ebml_tag {
+ auto id = read_vint(r.reader);
+ auto size = read_vint(r.reader);
+ ret rec(id=id, size=size);
+}
+
+// Reads a tag and moves the cursor to its first child or data segment.
+impure fn move_to_first_child(&reader r) {
+ auto pos = r.reader.tell();
+ auto t = read_tag(r);
+ r.states += vec(rec(ebml_tag=t, pos=pos));
+}
+
+// Reads a tag and skips over its contents, moving to its next sibling.
+impure fn move_to_next_sibling(&reader r) {
+ auto t = read_tag(r);
+ r.reader.seek(t.size as int, io.seek_cur);
+}
+
+// Moves to the parent of this tag.
+impure fn move_to_parent(&reader r) {
+ check (_vec.len[ebml_state](r.states) > 0u);
+ auto st = _vec.pop[ebml_state](r.states);
+ r.reader.seek(st.pos as int, io.seek_set);
+}
+
+// Reads the data segment of a tag.
+impure fn read_data(&reader r) -> vec[u8] {
+ ret r.reader.read_bytes(bytes_left(r));
+}
+
+impure fn peek(&reader r) -> ebml_tag {
+ check (bytes_left(r) > 0u);
+ auto pos = r.reader.tell();
+ auto t = read_tag(r);
+ r.reader.seek(pos as int, io.seek_set);
+ ret t;
+}
+
+
+// EBML writing
+
+type writer = rec(io.writer writer, mutable vec[ebml_state] states);
+
+// TODO
+
diff --git a/src/lib/std.rc b/src/lib/std.rc
index 7a3cdbb2..e434769a 100644
--- a/src/lib/std.rc
+++ b/src/lib/std.rc
@@ -77,6 +77,7 @@ mod dbg;
mod bitv;
mod sort;
mod sha1;
+mod ebml;
// Local Variables:
// mode: rust;