123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- namespace Invercargill.DataStructures {
- public class BinaryData : Enumerable<uint8>, Promotion<uint8>, Equatable<Enumerable<uint8>>, Hashable {
- public enum Endianness {
- Native,
- BigEndian,
- LittleEndian,
- }
- public Endianness endianness { get; set; }
- private Enumerable<Enumerable<uint8>> chunks;
- public override int? peek_count() {
- return null;
- }
- public override EnumerableInfo get_info() {
- return new EnumerableInfo.infer(this, EnumerableCategory.COMPUTED, chunks);
- }
- public override Tracker<uint8> get_tracker () {
- return chunks.select_many<uint8>(s => s).get_tracker();
- }
- public BinaryData() {
- chunks = new Series<Enumerable<uint8>>();
- endianness = Endianness.Native;
- }
- public BinaryData.from_enumerable(Enumerable<uint8> data) {
- chunks = Invercargill.single(data.to_buffer());
- endianness = Endianness.Native;
- }
- public BinaryData.from_bytes(Bytes data) {
- chunks = Invercargill.single(Wrap.array(data.get_data()));
- endianness = Endianness.Native;
- }
- public BinaryData.from_byte_array(uint8[] data) {
- chunks = Invercargill.single(Wrap.array(data));
- endianness = Endianness.Native;
- }
- public BinaryData.from_base64(string data) {
- chunks = Invercargill.single(Wrap.array(Base64.decode(data)));
- endianness = Endianness.Native;
- }
- public BinaryData.from_hex(string data) {
- var groomed = data.replace(" ", "").replace("-", "").replace(":", "").replace("0x", "");
- var buffer = new Buffer<uint8>(groomed.length/2);
- for(var i = 0; i < groomed.length/2; i++) {
- non_error(() => buffer[i] = (uint8)uint.parse(groomed[i*2:(i+1)*2], 16));
- }
- chunks = Invercargill.single(buffer);
- endianness = Endianness.Native;
- }
- public void append(Enumerable<uint8> data) {
- lock(chunks) {
- chunks = chunks.with(data);
- }
- }
- public void append_all(Enumerable<Enumerable<uint8>> data) {
- lock(chunks) {
- chunks = chunks.concat(data.to_buffer());
- }
- }
- public void prepend(Enumerable<uint8> data) {
- lock(chunks) {
- chunks = Invercargill.single(data).concat(chunks);
- }
- }
- public void prepend_all(Enumerable<Enumerable<uint8>> data) {
- lock(chunks) {
- chunks = data.concat(chunks.to_buffer());
- }
- }
- public void append_byte_array(uint8[] data) {
- append(Wrap.array(data));
- }
- public void append_bytes(Bytes data) {
- append_byte_array(data.get_data());
- }
- public void append_string(string str) {
- append_byte_array(get_string_data(str));
- }
- public void prepend_byte_array(uint8[] data) {
- prepend(Wrap.array(data));
- }
- public void prepend_bytes(Bytes data) {
- prepend_byte_array(data.get_data());
- }
- public void prepend_string(string str) {
- prepend_byte_array(get_string_data(str));
- }
-
- private uint8[] get_string_data(string str) {
- var data = str.data;
- return data;
- }
- public void push_int64(int64 value) {
- var chunk = new uint8[sizeof(int64)];
- int64 val;
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- Memory.copy(chunk, &val, sizeof(int64));
- append(Wrap.array(chunk));
- }
- public int64? read_int64(int index) {
- var data = skip(index).take((int)sizeof(int64)).to_array();
- if(data.length != sizeof(int64))
- return null;
- int64 value = 0;
- int64 val = 0;
- Memory.copy(&value, data, sizeof(int64));
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- return val;
- }
- public void push_all_int64(Enumerable<int64?> values) {
- values.iterate(i => push_int64(i));
- }
- public void push_uint64(uint64 value) {
- var chunk = new uint8[sizeof(uint64)];
- uint64 val;
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- Memory.copy(chunk, &val, sizeof(uint64));
- append(Wrap.array(chunk));
- }
- public uint64? read_uint64(int index) {
- var data = skip(index).take((int)sizeof(uint64)).to_array();
- if(data.length != sizeof(uint64))
- return null;
- uint64 value = 0;
- uint64 val = 0;
- Memory.copy(&value, data, sizeof(uint64));
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- return val;
- }
- public void push_all_uint64(Enumerable<uint64?> values) {
- values.iterate(i => push_uint64(i));
- }
- public bool equals(Enumerable<uint8> other) {
- return this == other || matches(other, (a, b) => a == b);
- }
- public uint hash_code() {
- return aggregate<uint>(5381, (h, b) => h * 33 + b);
- }
- public void push_int32(int32 value) {
- var chunk = new uint8[sizeof(int32)];
- int32 val;
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- Memory.copy(chunk, &val, sizeof(int32));
- append(Wrap.array(chunk));
- }
- public int32? read_int32(int index) {
- var data = skip(index).take((int)sizeof(int32)).to_array();
- if(data.length != sizeof(int32))
- return null;
- int32 value = 0;
- int32 val = 0;
- Memory.copy(&value, data, sizeof(int32));
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- return val;
- }
- public void push_all_int32(Enumerable<int32?> values) {
- values.iterate(i => push_int32(i));
- }
- public void push_uint32(uint32 value) {
- var chunk = new uint8[sizeof(uint32)];
- uint32 val;
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- Memory.copy(chunk, &val, sizeof(uint32));
- append(Wrap.array(chunk));
- }
- public uint32? read_uint32(int index) {
- var data = skip(index).take((int)sizeof(uint32)).to_array();
- if(data.length != sizeof(uint32))
- return null;
- uint32 value = 0;
- uint32 val = 0;
- Memory.copy(&value, data, sizeof(uint32));
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- return val;
- }
- public void push_all_uint32(Enumerable<uint32?> values) {
- values.iterate(i => push_uint32(i));
- }
- public void push_int16(int16 value) {
- var chunk = new uint8[sizeof(int16)];
- int16 val;
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- Memory.copy(chunk, &val, sizeof(int16));
- append(Wrap.array(chunk));
- }
- public int16? read_int16(int index) {
- var data = skip(index).take((int)sizeof(int16)).to_array();
- if(data.length != sizeof(int16))
- return null;
- int16 value = 0;
- int16 val = 0;
- Memory.copy(&value, data, sizeof(int16));
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- return val;
- }
- public void push_all_int16(Enumerable<int16?> values) {
- values.iterate(i => push_int16(i));
- }
- public void push_uint16(uint16 value) {
- var chunk = new uint8[sizeof(uint16)];
- uint16 val;
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- Memory.copy(chunk, &val, sizeof(uint16));
- append(Wrap.array(chunk));
- }
- public uint16? read_uint16(int index) {
- var data = skip(index).take((int)sizeof(uint16)).to_array();
- if(data.length != sizeof(uint16))
- return null;
- uint16 value = 0;
- uint16 val = 0;
- Memory.copy(&value, data, sizeof(uint16));
- switch (endianness) {
- case Endianness.Native:
- val = value;
- break;
- case Endianness.BigEndian:
- val = value.to_big_endian();
- break;
- case Endianness.LittleEndian:
- val = value.to_little_endian();
- break;
- }
- return val;
- }
- public void push_all_uint16(Enumerable<uint16?> values) {
- values.iterate(i => push_uint16(i));
- }
- public void push_int8(int8 value) {
- var chunk = new uint8[sizeof(int8)];
- Memory.copy(chunk, &value, sizeof(int8));
- append(Wrap.array(chunk));
- }
- public int8? read_int8(int index) {
- var data = skip(index).take((int)sizeof(int8)).to_array();
- if(data.length != sizeof(int8))
- return null;
- int8 value = 0;
- Memory.copy(&value, data, sizeof(int8));
- return value;
- }
- public void push_all_int8(Enumerable<int8?> values) {
- values.iterate(i => push_int8(i));
- }
- public void push_uint8(uint8 value) {
- var chunk = new uint8[] { value };
- append(Wrap.array(chunk));
- }
- public uint8? read_uint8(int index) {
- var data = skip(index).take((int)sizeof(uint8)).to_array();
- if(data.length != sizeof(uint8))
- return null;
- uint8 value = 0;
- Memory.copy(&value, data, sizeof(uint8));
- return value;
- }
- public void push_all_uint8(Enumerable<uint8?> values) {
- values.iterate(i => push_uint8(i));
- }
- public string to_escaped_string() {
- var builder = new StringBuilder();
- foreach (var byte in this) {
- if(byte >= 32 && byte <= 126) {
- builder.append_unichar((unichar)byte);
- }
- else {
- builder.append(@"[$(byte)d]");
- }
- }
- return builder.str;
- }
- public string to_raw_string(bool null_terminate = true) {
- Enumerable<uint8> data = this;
- if(null_terminate) {
- data.concat(Invercargill.single<uint8>(0));
- }
- return (string)data.to_array();
- }
- public string to_base64() {
- return Base64.encode(to_array());
- }
- public string to_hex() {
- return to_string(i => i.to_string("%x"));
- }
- public Bytes to_bytes() {
- return new Bytes(to_array());
- }
- public BinaryData slice(int start, int end) {
- return new BinaryData.from_enumerable(skip(start).take(end-start));
- }
- public BinaryData read(int start, int length) {
- return new BinaryData.from_enumerable(skip(start).take(length));
- }
- public bool read_in(Bytes? data, ref size_t amount) throws Error {
- if(amount <= 0) {
- return false;
- }
- if(data == null) {
- return true;
- }
- if(data.length == 0) {
- throw new BinaryDataReadError.EMPTY_READ("Encounterd zero-length data object");
- }
- if(data.length > amount) {
- throw new BinaryDataReadError.BUFFER_OVERFLOW("Encountered more data than requested");
- }
- var bin = new uint8[data.length];
- Memory.copy(bin, data.get_data(), data.length);
- append_byte_array(bin);
- amount -= data.length;
- return amount != 0;
- }
- public Enumerable<uint8> wrap(Enumerable<uint8> enumerable) {
- chunks = Invercargill.single(enumerable);
- return this;
- }
- public bool can_wrap(Type element_type) {
- return element_type.is_a(typeof(uint8));
- }
- public size_t write_to(void* array, size_t max_size) {
- var data = to_array();
- var size = max_size > data.length ? data.length : max_size;
- Memory.copy(array, data, size);
- return size;
- }
- }
- }
|