|
@@ -1,506 +0,0 @@
|
|
|
-
|
|
|
-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;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-}
|