From b6d774136b62b2df51555a325439126a29038da3 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 11 Jul 2011 11:50:02 -0700 Subject: [PATCH] stdlib: Add interior vector-ified versions of ebml and term --- src/lib/ebmlivec.rs | 172 ++++++++++++++++++++++++++++++++++++++++++++ src/lib/std.rc | 2 + src/lib/termivec.rs | 81 +++++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 src/lib/ebmlivec.rs create mode 100644 src/lib/termivec.rs diff --git a/src/lib/ebmlivec.rs b/src/lib/ebmlivec.rs new file mode 100644 index 00000000000..64b9db5b2d0 --- /dev/null +++ b/src/lib/ebmlivec.rs @@ -0,0 +1,172 @@ + + +// 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 tag_pos, uint data_pos); + + +// TODO: When we have module renaming, make "reader" and "writer" separate +// modules within this file. + +// ebml reading +type doc = rec(u8[] data, uint start, uint end); + +fn vint_at(&u8[] data, uint start) -> tup(uint, uint) { + auto a = data.(start); + if (a & 0x80u8 != 0u8) { ret tup(a & 0x7fu8 as uint, start + 1u); } + if (a & 0x40u8 != 0u8) { + ret tup((a & 0x3fu8 as uint) << 8u | (data.(start + 1u) as uint), + start + 2u); + } else if (a & 0x20u8 != 0u8) { + ret tup((a & 0x1fu8 as uint) << 16u | + (data.(start + 1u) as uint) << 8u | + (data.(start + 2u) as uint), start + 3u); + } else if (a & 0x10u8 != 0u8) { + ret tup((a & 0x0fu8 as uint) << 24u | + (data.(start + 1u) as uint) << 16u | + (data.(start + 2u) as uint) << 8u | + (data.(start + 3u) as uint), start + 4u); + } else { log_err "vint too big"; fail; } +} + +fn new_doc(&u8[] data) -> doc { + ret rec(data=data, start=0u, end=ivec::len[u8](data)); +} + +fn doc_at(&u8[] data, uint start) -> doc { + auto elt_tag = vint_at(data, start); + auto elt_size = vint_at(data, elt_tag._1); + auto end = elt_size._1 + elt_size._0; + ret rec(data=data, start=elt_size._1, end=end); +} + +fn maybe_get_doc(doc d, uint tg) -> option::t[doc] { + auto pos = d.start; + while (pos < d.end) { + auto elt_tag = vint_at(d.data, pos); + auto elt_size = vint_at(d.data, elt_tag._1); + pos = elt_size._1 + elt_size._0; + if (elt_tag._0 == tg) { + ret some[doc](rec(data=d.data, start=elt_size._1, end=pos)); + } + } + ret none[doc]; +} + +fn get_doc(doc d, uint tg) -> doc { + alt (maybe_get_doc(d, tg)) { + case (some(?d)) { ret d; } + case (none) { + log_err "failed to find block with tag " + uint::to_str(tg, 10u); + fail; + } + } +} + +iter docs(doc d) -> tup(uint, doc) { + auto pos = d.start; + while (pos < d.end) { + auto elt_tag = vint_at(d.data, pos); + auto elt_size = vint_at(d.data, elt_tag._1); + pos = elt_size._1 + elt_size._0; + put tup(elt_tag._0, rec(data=d.data, start=elt_size._1, end=pos)); + } +} + +iter tagged_docs(doc d, uint tg) -> doc { + auto pos = d.start; + while (pos < d.end) { + auto elt_tag = vint_at(d.data, pos); + auto elt_size = vint_at(d.data, elt_tag._1); + pos = elt_size._1 + elt_size._0; + if (elt_tag._0 == tg) { + put rec(data=d.data, start=elt_size._1, end=pos); + } + } +} + +fn doc_data(doc d) -> u8[] { ret ivec::slice[u8](d.data, d.start, d.end); } + +fn be_uint_from_bytes(&u8[] data, uint start, uint size) -> uint { + auto sz = size; + assert (sz <= 4u); + auto val = 0u; + auto pos = start; + while (sz > 0u) { + sz -= 1u; + val += (data.(pos) as uint) << sz * 8u; + pos += 1u; + } + ret val; +} + +fn doc_as_uint(doc d) -> uint { + ret be_uint_from_bytes(d.data, d.start, d.end - d.start); +} + + +// ebml writing +type writer = rec(ioivec::buf_writer writer, mutable uint[] size_positions); + +fn write_sized_vint(&ioivec::buf_writer w, uint n, uint size) { + let u8[] buf; + alt (size) { + case (1u) { buf = ~[0x80u8 | (n as u8)]; } + case (2u) { buf = ~[0x40u8 | (n >> 8u as u8), n & 0xffu as u8]; } + case (3u) { + buf = + ~[0x20u8 | (n >> 16u as u8), n >> 8u & 0xffu as u8, + n & 0xffu as u8]; + } + case (4u) { + buf = + ~[0x10u8 | (n >> 24u as u8), n >> 16u & 0xffu as u8, + n >> 8u & 0xffu as u8, n & 0xffu as u8]; + } + case (_) { log_err "vint to write too big"; fail; } + } + w.write(buf); +} + +fn write_vint(&ioivec::buf_writer w, uint n) { + if (n < 0x7fu) { write_sized_vint(w, n, 1u); ret; } + if (n < 0x4000u) { write_sized_vint(w, n, 2u); ret; } + if (n < 0x200000u) { write_sized_vint(w, n, 3u); ret; } + if (n < 0x10000000u) { write_sized_vint(w, n, 4u); ret; } + log_err "vint to write too big"; + fail; +} + +fn create_writer(&ioivec::buf_writer w) -> writer { + let uint[] size_positions = ~[]; + ret rec(writer=w, mutable size_positions=size_positions); +} + + +// TODO: Provide a function to write the standard ebml header. +fn start_tag(&writer w, uint tag_id) { + // Write the tag ID: + + write_vint(w.writer, tag_id); + // Write a placeholder four-byte size. + + w.size_positions += ~[w.writer.tell()]; + let u8[] zeroes = ~[0u8, 0u8, 0u8, 0u8]; + w.writer.write(zeroes); +} + +fn end_tag(&writer w) { + auto last_size_pos = ivec::pop[uint](w.size_positions); + auto cur_pos = w.writer.tell(); + w.writer.seek(last_size_pos as int, ioivec::seek_set); + write_sized_vint(w.writer, cur_pos - last_size_pos - 4u, 4u); + w.writer.seek(cur_pos as int, ioivec::seek_set); +} +// TODO: optionally perform "relaxations" on end_tag to more efficiently +// encode sizes; this is a fixed point iteration diff --git a/src/lib/std.rc b/src/lib/std.rc index 07833b7eea5..622a9563c87 100644 --- a/src/lib/std.rc +++ b/src/lib/std.rc @@ -90,6 +90,8 @@ mod smallintmap; mod ptr; mod test; mod unsafe; +mod ebmlivec; +mod termivec; // Local Variables: // mode: rust; diff --git a/src/lib/termivec.rs b/src/lib/termivec.rs new file mode 100644 index 00000000000..d80c17fcf62 --- /dev/null +++ b/src/lib/termivec.rs @@ -0,0 +1,81 @@ + + + +// Simple ANSI color library. +// +// TODO: Windows support. +const u8 color_black = 0u8; + +const u8 color_red = 1u8; + +const u8 color_green = 2u8; + +const u8 color_yellow = 3u8; + +const u8 color_blue = 4u8; + +const u8 color_magenta = 5u8; + +const u8 color_cyan = 6u8; + +const u8 color_light_gray = 7u8; + +const u8 color_light_grey = 7u8; + +const u8 color_dark_gray = 8u8; + +const u8 color_dark_grey = 8u8; + +const u8 color_bright_red = 9u8; + +const u8 color_bright_green = 10u8; + +const u8 color_bright_yellow = 11u8; + +const u8 color_bright_blue = 12u8; + +const u8 color_bright_magenta = 13u8; + +const u8 color_bright_cyan = 14u8; + +const u8 color_bright_white = 15u8; + +fn esc(ioivec::buf_writer writer) { writer.write(~[0x1bu8, '[' as u8]); } + +fn reset(ioivec::buf_writer writer) { + esc(writer); + writer.write(~['0' as u8, 'm' as u8]); +} + +fn color_supported() -> bool { + auto supported_terms = ["xterm-color", "xterm", "screen-bce"]; + ret alt (generic_os::getenv("TERM")) { + case (option::some(?env)) { vec::member(env, supported_terms) } + case (option::none) { false } + }; +} + +fn set_color(ioivec::buf_writer writer, u8 first_char, u8 color) { + assert (color < 16u8); + esc(writer); + if (color >= 8u8) { writer.write(~['1' as u8, ';' as u8]); color -= 8u8; } + writer.write(~[first_char, ('0' as u8) + color, 'm' as u8]); +} + +fn fg(ioivec::buf_writer writer, u8 color) { + ret set_color(writer, '3' as u8, color); +} + +fn bg(ioivec::buf_writer writer, u8 color) { + ret set_color(writer, '4' as u8, color); +} +// export fg; +// export bg; + +// Local Variables: +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: