BinaryData.vala 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. namespace Invercargill.DataStructures {
  2. public class BinaryData : Enumerable<uint8>, Promotion<uint8>, Equatable<Enumerable<uint8>>, Hashable {
  3. public enum Endianness {
  4. Native,
  5. BigEndian,
  6. LittleEndian,
  7. }
  8. public Endianness endianness { get; set; }
  9. private Enumerable<Enumerable<uint8>> chunks;
  10. public override int? peek_count() {
  11. return null;
  12. }
  13. public override EnumerableInfo get_info() {
  14. return new EnumerableInfo.infer(this, EnumerableCategory.COMPUTED, chunks);
  15. }
  16. public override Tracker<uint8> get_tracker () {
  17. return chunks.select_many<uint8>(s => s).get_tracker();
  18. }
  19. public BinaryData() {
  20. chunks = new Series<Enumerable<uint8>>();
  21. endianness = Endianness.Native;
  22. }
  23. public BinaryData.from_enumerable(Enumerable<uint8> data) {
  24. chunks = Invercargill.single(data.to_buffer());
  25. endianness = Endianness.Native;
  26. }
  27. public BinaryData.from_bytes(Bytes data) {
  28. chunks = Invercargill.single(Wrap.array(data.get_data()));
  29. endianness = Endianness.Native;
  30. }
  31. public BinaryData.from_byte_array(uint8[] data) {
  32. chunks = Invercargill.single(Wrap.array(data));
  33. endianness = Endianness.Native;
  34. }
  35. public BinaryData.from_base64(string data) {
  36. chunks = Invercargill.single(Wrap.array(Base64.decode(data)));
  37. endianness = Endianness.Native;
  38. }
  39. public BinaryData.from_hex(string data) {
  40. var groomed = data.replace(" ", "").replace("-", "").replace(":", "").replace("0x", "");
  41. var buffer = new Buffer<uint8>(groomed.length/2);
  42. for(var i = 0; i < groomed.length/2; i++) {
  43. non_error(() => buffer[i] = (uint8)uint.parse(groomed[i*2:(i+1)*2], 16));
  44. }
  45. chunks = Invercargill.single(buffer);
  46. endianness = Endianness.Native;
  47. }
  48. public void append(Enumerable<uint8> data) {
  49. lock(chunks) {
  50. chunks = chunks.with(data);
  51. }
  52. }
  53. public void append_all(Enumerable<Enumerable<uint8>> data) {
  54. lock(chunks) {
  55. chunks = chunks.concat(data.to_buffer());
  56. }
  57. }
  58. public void prepend(Enumerable<uint8> data) {
  59. lock(chunks) {
  60. chunks = Invercargill.single(data).concat(chunks);
  61. }
  62. }
  63. public void prepend_all(Enumerable<Enumerable<uint8>> data) {
  64. lock(chunks) {
  65. chunks = data.concat(chunks.to_buffer());
  66. }
  67. }
  68. public void append_byte_array(uint8[] data) {
  69. append(Wrap.array(data));
  70. }
  71. public void append_bytes(Bytes data) {
  72. append_byte_array(data.get_data());
  73. }
  74. public void append_string(string str) {
  75. append_byte_array(get_string_data(str));
  76. }
  77. public void prepend_byte_array(uint8[] data) {
  78. prepend(Wrap.array(data));
  79. }
  80. public void prepend_bytes(Bytes data) {
  81. prepend_byte_array(data.get_data());
  82. }
  83. public void prepend_string(string str) {
  84. prepend_byte_array(get_string_data(str));
  85. }
  86. private uint8[] get_string_data(string str) {
  87. var data = str.data;
  88. return data;
  89. }
  90. public void push_int64(int64 value) {
  91. var chunk = new uint8[sizeof(int64)];
  92. int64 val;
  93. switch (endianness) {
  94. case Endianness.Native:
  95. val = value;
  96. break;
  97. case Endianness.BigEndian:
  98. val = value.to_big_endian();
  99. break;
  100. case Endianness.LittleEndian:
  101. val = value.to_little_endian();
  102. break;
  103. }
  104. Memory.copy(chunk, &val, sizeof(int64));
  105. append(Wrap.array(chunk));
  106. }
  107. public int64? read_int64(int index) {
  108. var data = skip(index).take((int)sizeof(int64)).to_array();
  109. if(data.length != sizeof(int64))
  110. return null;
  111. int64 value = 0;
  112. int64 val = 0;
  113. Memory.copy(&value, data, sizeof(int64));
  114. switch (endianness) {
  115. case Endianness.Native:
  116. val = value;
  117. break;
  118. case Endianness.BigEndian:
  119. val = value.to_big_endian();
  120. break;
  121. case Endianness.LittleEndian:
  122. val = value.to_little_endian();
  123. break;
  124. }
  125. return val;
  126. }
  127. public void push_all_int64(Enumerable<int64?> values) {
  128. values.iterate(i => push_int64(i));
  129. }
  130. public void push_uint64(uint64 value) {
  131. var chunk = new uint8[sizeof(uint64)];
  132. uint64 val;
  133. switch (endianness) {
  134. case Endianness.Native:
  135. val = value;
  136. break;
  137. case Endianness.BigEndian:
  138. val = value.to_big_endian();
  139. break;
  140. case Endianness.LittleEndian:
  141. val = value.to_little_endian();
  142. break;
  143. }
  144. Memory.copy(chunk, &val, sizeof(uint64));
  145. append(Wrap.array(chunk));
  146. }
  147. public uint64? read_uint64(int index) {
  148. var data = skip(index).take((int)sizeof(uint64)).to_array();
  149. if(data.length != sizeof(uint64))
  150. return null;
  151. uint64 value = 0;
  152. uint64 val = 0;
  153. Memory.copy(&value, data, sizeof(uint64));
  154. switch (endianness) {
  155. case Endianness.Native:
  156. val = value;
  157. break;
  158. case Endianness.BigEndian:
  159. val = value.to_big_endian();
  160. break;
  161. case Endianness.LittleEndian:
  162. val = value.to_little_endian();
  163. break;
  164. }
  165. return val;
  166. }
  167. public void push_all_uint64(Enumerable<uint64?> values) {
  168. values.iterate(i => push_uint64(i));
  169. }
  170. public bool equals(Enumerable<uint8> other) {
  171. return this == other || matches(other, (a, b) => a == b);
  172. }
  173. public uint hash_code() {
  174. return aggregate<uint>(5381, (h, b) => h * 33 + b);
  175. }
  176. public void push_int32(int32 value) {
  177. var chunk = new uint8[sizeof(int32)];
  178. int32 val;
  179. switch (endianness) {
  180. case Endianness.Native:
  181. val = value;
  182. break;
  183. case Endianness.BigEndian:
  184. val = value.to_big_endian();
  185. break;
  186. case Endianness.LittleEndian:
  187. val = value.to_little_endian();
  188. break;
  189. }
  190. Memory.copy(chunk, &val, sizeof(int32));
  191. append(Wrap.array(chunk));
  192. }
  193. public int32? read_int32(int index) {
  194. var data = skip(index).take((int)sizeof(int32)).to_array();
  195. if(data.length != sizeof(int32))
  196. return null;
  197. int32 value = 0;
  198. int32 val = 0;
  199. Memory.copy(&value, data, sizeof(int32));
  200. switch (endianness) {
  201. case Endianness.Native:
  202. val = value;
  203. break;
  204. case Endianness.BigEndian:
  205. val = value.to_big_endian();
  206. break;
  207. case Endianness.LittleEndian:
  208. val = value.to_little_endian();
  209. break;
  210. }
  211. return val;
  212. }
  213. public void push_all_int32(Enumerable<int32?> values) {
  214. values.iterate(i => push_int32(i));
  215. }
  216. public void push_uint32(uint32 value) {
  217. var chunk = new uint8[sizeof(uint32)];
  218. uint32 val;
  219. switch (endianness) {
  220. case Endianness.Native:
  221. val = value;
  222. break;
  223. case Endianness.BigEndian:
  224. val = value.to_big_endian();
  225. break;
  226. case Endianness.LittleEndian:
  227. val = value.to_little_endian();
  228. break;
  229. }
  230. Memory.copy(chunk, &val, sizeof(uint32));
  231. append(Wrap.array(chunk));
  232. }
  233. public uint32? read_uint32(int index) {
  234. var data = skip(index).take((int)sizeof(uint32)).to_array();
  235. if(data.length != sizeof(uint32))
  236. return null;
  237. uint32 value = 0;
  238. uint32 val = 0;
  239. Memory.copy(&value, data, sizeof(uint32));
  240. switch (endianness) {
  241. case Endianness.Native:
  242. val = value;
  243. break;
  244. case Endianness.BigEndian:
  245. val = value.to_big_endian();
  246. break;
  247. case Endianness.LittleEndian:
  248. val = value.to_little_endian();
  249. break;
  250. }
  251. return val;
  252. }
  253. public void push_all_uint32(Enumerable<uint32?> values) {
  254. values.iterate(i => push_uint32(i));
  255. }
  256. public void push_int16(int16 value) {
  257. var chunk = new uint8[sizeof(int16)];
  258. int16 val;
  259. switch (endianness) {
  260. case Endianness.Native:
  261. val = value;
  262. break;
  263. case Endianness.BigEndian:
  264. val = value.to_big_endian();
  265. break;
  266. case Endianness.LittleEndian:
  267. val = value.to_little_endian();
  268. break;
  269. }
  270. Memory.copy(chunk, &val, sizeof(int16));
  271. append(Wrap.array(chunk));
  272. }
  273. public int16? read_int16(int index) {
  274. var data = skip(index).take((int)sizeof(int16)).to_array();
  275. if(data.length != sizeof(int16))
  276. return null;
  277. int16 value = 0;
  278. int16 val = 0;
  279. Memory.copy(&value, data, sizeof(int16));
  280. switch (endianness) {
  281. case Endianness.Native:
  282. val = value;
  283. break;
  284. case Endianness.BigEndian:
  285. val = value.to_big_endian();
  286. break;
  287. case Endianness.LittleEndian:
  288. val = value.to_little_endian();
  289. break;
  290. }
  291. return val;
  292. }
  293. public void push_all_int16(Enumerable<int16?> values) {
  294. values.iterate(i => push_int16(i));
  295. }
  296. public void push_uint16(uint16 value) {
  297. var chunk = new uint8[sizeof(uint16)];
  298. uint16 val;
  299. switch (endianness) {
  300. case Endianness.Native:
  301. val = value;
  302. break;
  303. case Endianness.BigEndian:
  304. val = value.to_big_endian();
  305. break;
  306. case Endianness.LittleEndian:
  307. val = value.to_little_endian();
  308. break;
  309. }
  310. Memory.copy(chunk, &val, sizeof(uint16));
  311. append(Wrap.array(chunk));
  312. }
  313. public uint16? read_uint16(int index) {
  314. var data = skip(index).take((int)sizeof(uint16)).to_array();
  315. if(data.length != sizeof(uint16))
  316. return null;
  317. uint16 value = 0;
  318. uint16 val = 0;
  319. Memory.copy(&value, data, sizeof(uint16));
  320. switch (endianness) {
  321. case Endianness.Native:
  322. val = value;
  323. break;
  324. case Endianness.BigEndian:
  325. val = value.to_big_endian();
  326. break;
  327. case Endianness.LittleEndian:
  328. val = value.to_little_endian();
  329. break;
  330. }
  331. return val;
  332. }
  333. public void push_all_uint16(Enumerable<uint16?> values) {
  334. values.iterate(i => push_uint16(i));
  335. }
  336. public void push_int8(int8 value) {
  337. var chunk = new uint8[sizeof(int8)];
  338. Memory.copy(chunk, &value, sizeof(int8));
  339. append(Wrap.array(chunk));
  340. }
  341. public int8? read_int8(int index) {
  342. var data = skip(index).take((int)sizeof(int8)).to_array();
  343. if(data.length != sizeof(int8))
  344. return null;
  345. int8 value = 0;
  346. Memory.copy(&value, data, sizeof(int8));
  347. return value;
  348. }
  349. public void push_all_int8(Enumerable<int8?> values) {
  350. values.iterate(i => push_int8(i));
  351. }
  352. public void push_uint8(uint8 value) {
  353. var chunk = new uint8[] { value };
  354. append(Wrap.array(chunk));
  355. }
  356. public uint8? read_uint8(int index) {
  357. var data = skip(index).take((int)sizeof(uint8)).to_array();
  358. if(data.length != sizeof(uint8))
  359. return null;
  360. uint8 value = 0;
  361. Memory.copy(&value, data, sizeof(uint8));
  362. return value;
  363. }
  364. public void push_all_uint8(Enumerable<uint8?> values) {
  365. values.iterate(i => push_uint8(i));
  366. }
  367. public string to_escaped_string() {
  368. var builder = new StringBuilder();
  369. foreach (var byte in this) {
  370. if(byte >= 32 && byte <= 126) {
  371. builder.append_unichar((unichar)byte);
  372. }
  373. else {
  374. builder.append(@"[$(byte)d]");
  375. }
  376. }
  377. return builder.str;
  378. }
  379. public string to_raw_string(bool null_terminate = true) {
  380. Enumerable<uint8> data = this;
  381. if(null_terminate) {
  382. data.concat(Invercargill.single<uint8>(0));
  383. }
  384. return (string)data.to_array();
  385. }
  386. public string to_base64() {
  387. return Base64.encode(to_array());
  388. }
  389. public string to_hex() {
  390. return to_string(i => i.to_string("%x"));
  391. }
  392. public Bytes to_bytes() {
  393. return new Bytes(to_array());
  394. }
  395. public BinaryData slice(int start, int end) {
  396. return new BinaryData.from_enumerable(skip(start).take(end-start));
  397. }
  398. public BinaryData read(int start, int length) {
  399. return new BinaryData.from_enumerable(skip(start).take(length));
  400. }
  401. public bool read_in(Bytes? data, ref size_t amount) throws Error {
  402. if(amount <= 0) {
  403. return false;
  404. }
  405. if(data == null) {
  406. return true;
  407. }
  408. if(data.length == 0) {
  409. throw new BinaryDataReadError.EMPTY_READ("Encounterd zero-length data object");
  410. }
  411. if(data.length > amount) {
  412. throw new BinaryDataReadError.BUFFER_OVERFLOW("Encountered more data than requested");
  413. }
  414. var bin = new uint8[data.length];
  415. Memory.copy(bin, data.get_data(), data.length);
  416. append_byte_array(bin);
  417. amount -= data.length;
  418. return amount != 0;
  419. }
  420. public Enumerable<uint8> wrap(Enumerable<uint8> enumerable) {
  421. chunks = Invercargill.single(enumerable);
  422. return this;
  423. }
  424. public bool can_wrap(Type element_type) {
  425. return element_type.is_a(typeof(uint8));
  426. }
  427. public size_t write_to(void* array, size_t max_size) {
  428. var data = to_array();
  429. var size = max_size > data.length ? data.length : max_size;
  430. Memory.copy(array, data, size);
  431. return size;
  432. }
  433. }
  434. }