Link Search Menu Expand Document

Working with Binary data

Working with binary data in Blade is a simple as working with lists and this can be done using bytes. A bytes (meaning Byte stream) is an iterable in-memory contiguous list of numbers. Blade allows easily creating bytes from strings and vice-versa and they are the primary medium of reading and writing binary data into and from the OS.

The built-in bytes() function can be used to create a byte stream. For example,

%> bytes(5)
(0 0 0 0 0)

The above code creates a byte stream containing five bytes all initialized to zero (0). You can also create byte stream from a list of numbers as well. For example,

%> bytes([72, 69, 76, 76, 79])
(48 45 4c 4c 4f)

The above code creates a byte stream sequence corresponding to HELLO in memory.

Byte streams are like lists and they can be extended, conncatenated and more. They allow us operate on binary data.

One very important use-case for bytes are to create a file containing binary data, the file.write() API expects to write byte streams to file when the file is opened in the binary mode and the most basic way of providing it with such data is by using bytes.

For example,

%> file('dummy.txt', 'wb').write(bytes([72, 69, 76, 76, 79]))
true
%> file('dummy.txt').read()
'HELLO'

In the above sample, we wrote the bytes we created ealier into a file and read its contents.

When a byte stream is created using a list of numbers, the maximum number that will be interpreted as is is 255. All numbers exceeding that amount will be equal to (number % 255) - 1.

E.g.

%> bytes([256])
(0)
%> bytes([386])
(82)
%> 0x82
130
%> (386 % 255) - 1
130

Byte stream indexing


Like Lists, Strings and Dictionaries, Byte streams can also be indexed in Blade. We can retrieve an index in a byte stream using the same operators as others ([]) and we can use this to access or modify the contents of a byte stream.

For example,

%> var g = bytes([31, 47, 83, 105, 72])
%> g
(1f 2f 53 69 48)
%> g[3]
105
%> g[1,3]
(2f 53)
%> g[2] = 96
%> g
(1f 2f 60 69 48)

bytes() methods


The byte stram object contains the following methods:

NOTE: Byte streams are printed as hexadecimal lists.

bytes(value: number | list)
Creates a new byte stream
  • if a number is given, creates an array of size number
  • if a list is given, converts the bytes list into an array of bytes.

For example,

%> bytes(5)
(0 0 0 0 0)
%> bytes([65, 66, 67, 68, 69])
(41 42 43 44 45)
bytes.length()
Returns the length of a byte stream.

For example,

%> bytes([25, 57]).length()
2
bytes.append(item: any)
Adds an item to the top of a byte stream.

For example,

%> var a = bytes([0x40, 0x75])
%> a.append(0x16)
%> echo a
(40 75 16)
bytes.clone()
Returns a deep clone of the byte stream.

For example,

%> bytes([19, 11]).clone()
(13 b)
bytes.extend(item: bytes2)
Adds the content of byte stream 2 into byte stream.

For example,

%> var a = bytes([33, 91, 126])
%> var b = bytes([119, 42])
%> a
(21 5b 7e)
%> b
(77 2a)
%> a.extend(b)
(21 5b 7e 77 2a)
%> a
(21 5b 7e 77 2a)

@note: extend() is an in-place action so the original byte stream will be modified.

bytes.pop()
Removes the last item in a byte stream and returns it.

For example,

%> var a = bytes([79, 43, 9])
%> a.pop()
9
%> a
(4f 2b)
bytes.remove(index: number)
Removes the item at the specified index in the byte stream.

For example,

%> var a = bytes([79, 43, 9, 139])
%> a.remove(1)
43
%> a
(4f 9 8b)
bytes.reverse()
Reverses the items in a byte stream.

For example,

%> bytes([1, 2, 3, 4, 5]).reverse()
(5 4 3 2 1)
bytes.first()
Returns the first item in a byte stream or nil if the byte stream is empty.

For example,

%> bytes([14, 93, 37]).first()
14
bytes.last()
Returns the last item in a byte stream or nil if the byte stream is empty.

For example,

%> bytes([14, 93, 37]).last()
37
bytes.get(index: number)
Returns the value at index in the byte stream.

For example,

%> bytes([1, 2, 3, 4, 5]).get(3)
4
bytes.split(delimiter: bytes)
Splits the content of a byte stream based on the specified delimiter.

For example,

%> bytes(0).split(bytes(0))
[]
%> echo 'test'.to_bytes().split(bytes(0))
[(74), (65), (73), (74)]
bytes.is_alpha()
Returns true if the byte stream contains only alphabets.

For example,

%> bytes([25, 57]).is_alpha()
false
%> bytes([65, 66]).is_alpha()
true
bytes.is_alnum()
Returns true if the byte stream contains only number and alphabets.

For example,

%> bytes([25, 57]).is_alnum()
false
%> bytes([65, 66]).is_alnum()
true
%> bytes([97, 66]).is_alnum()
true
bytes.is_number()
Returns true if the byte stream contains only number.

For example,

%> bytes([60, 61]).is_number()
false
%> bytes([49, 51]).is_number()
true
bytes.is_lower()
Returns true if all the text in the byte stream are lower case.

For example,

%> bytes([97]).is_lower()
true
%> bytes([77]).is_lower()
false
bytes.is_upper()
Returns true if all the text in the byte stream are capital case.

For example,

%> bytes([97]).is_upper()
false
%> bytes([67]).is_upper()
true
bytes.is_space()
Returns true is the byte stream contains only white space.

For example,

%> bytes([13]).is_space() # 13 is the character number for ENTER
true
%> bytes([33]).is_space()
false
bytes.dispose()
Due to the nature of byte stream and their use-case (especially streaming data), it is easy for the system memory to get filled up with data in the byte stream. The method allows users to reset a byte stream and empty it.

This allows manual memory management of byte stream.

For example,

%> var a = bytes([13, 36])
%> a.dispose()
%> a
()
bytes.to_list()
Returns a list of every byte in the byte stream.

For example,

%> bytes([0x31, 0x55, 0x149, 0x215]).to_list()
[49, 85, 73, 21]
bytes.to_string()
Returns a string representation of the byte stream.

For example,

%> bytes([65, 66, 67, 68, 69]).to_string()
'ABCDE'

Previous Topic


Back to top

Copyright © 2021 Ore Richard Muyiwa. Distributed under the MIT license.