|
@@ -0,0 +1,215 @@
|
|
|
+namespace Invercargill {
|
|
|
+
|
|
|
+ public class BinaryData : Enumerable<uint8> {
|
|
|
+
|
|
|
+ public enum Endianness {
|
|
|
+ Native,
|
|
|
+ BigEndian,
|
|
|
+ LittleEndian,
|
|
|
+ }
|
|
|
+
|
|
|
+ public Endianness endianness { get; set; }
|
|
|
+
|
|
|
+ private Enumerable<Enumerable<uint8>> chunks;
|
|
|
+
|
|
|
+ public override Tracker<uint8> get_tracker () {
|
|
|
+ return chunks.select_many<uint8>(s => s).get_tracker();
|
|
|
+ }
|
|
|
+
|
|
|
+ public BinaryData() {
|
|
|
+ chunks = new Sequence<Enumerable<uint8>>();
|
|
|
+ endianness = Endianness.Native;
|
|
|
+ }
|
|
|
+
|
|
|
+ public BinaryData.from_enumerable(Enumerable<uint8> data) {
|
|
|
+ chunks = Invercargill.single(data.to_sequence());
|
|
|
+ endianness = Endianness.Native;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void append(Enumerable<uint8> data) {
|
|
|
+ lock(chunks) {
|
|
|
+ chunks = chunks.with(data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void prepend(Enumerable<uint8> data) {
|
|
|
+ lock(chunks) {
|
|
|
+ chunks = Invercargill.single(data).concat(chunks);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void append_byte_array(uint8[] data) {
|
|
|
+ append(ate(data.copy()));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void append_bytes(Bytes data) {
|
|
|
+ append_byte_array(data.get_data());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void append_string(string str, bool remove_null_termination = true) {
|
|
|
+ append_byte_array(get_string_data(str, remove_null_termination));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void prepend_byte_array(uint8[] data) {
|
|
|
+ prepend(ate(data.copy()));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void prepend_bytes(Bytes data) {
|
|
|
+ prepend_byte_array(data.get_data());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void prepend_string(string str, bool remove_null_termination = true) {
|
|
|
+ prepend_byte_array(get_string_data(str, remove_null_termination));
|
|
|
+ }
|
|
|
+
|
|
|
+ private uint8[] get_string_data(string str, bool remove_null_termination) {
|
|
|
+ var data = (uint8[])str;
|
|
|
+ if(remove_null_termination) {
|
|
|
+ data = data[0:-1];
|
|
|
+ }
|
|
|
+ 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(ate(chunk));
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(ate(chunk));
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(ate(chunk));
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(ate(chunk));
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(ate(chunk));
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(ate(chunk));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void push_int8(int8 value) {
|
|
|
+ var chunk = new uint8[sizeof(int8)];
|
|
|
+ Memory.copy(chunk, &value, sizeof(int8));
|
|
|
+ append(ate(chunk));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void push_uint8(uint8 value) {
|
|
|
+ var chunk = new uint8[] { value };
|
|
|
+ append(ate(chunk));
|
|
|
+ }
|
|
|
+
|
|
|
+ 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_base64() {
|
|
|
+ return Base64.encode(to_array());
|
|
|
+ }
|
|
|
+
|
|
|
+ public BinaryData slice(int start, int end) {
|
|
|
+ return new BinaryData.from_enumerable(skip(start).take(end-start));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|