+ return new FlatString.with_infos(outns, ln * 2, 0)
+ end
+
+ # Return a `Bytes` instance where Nit escape sequences are transformed.
+ #
+ # assert "B\\n\\x41\\u0103D3".unescape_to_bytes.hexdigest == "420A41F0908F93"
+ #
+ # `Bytes::chexdigest` is a loosely reverse methods since its result is only made
+ # of `"\x??"` escape sequences.
+ #
+ # assert "\\x41\\x42\\x43".unescape_to_bytes.chexdigest == "\\x41\\x42\\x43"
+ # assert "B\\n\\x41\\u0103D3".unescape_to_bytes.chexdigest == "\\x42\\x0A\\x41\\xF0\\x90\\x8F\\x93"
+ fun unescape_to_bytes: Bytes do
+ var res = new Bytes.with_capacity(self.byte_length)
+ var was_slash = false
+ var i = 0
+ while i < length do
+ var c = self[i]
+ if not was_slash then
+ if c == '\\' then
+ was_slash = true
+ else
+ res.add_char(c)
+ end
+ i += 1
+ continue
+ end
+ was_slash = false
+ if c == 'n' then
+ res.add_char('\n')
+ else if c == 'r' then
+ res.add_char('\r')
+ else if c == 't' then
+ res.add_char('\t')
+ else if c == '0' then
+ res.add_char('\0')
+ else if c == 'x' or c == 'X' then
+ var hx = substring(i + 1, 2)
+ if hx.is_hex then
+ res.add(hx.to_hex.to_b)
+ else
+ res.add_char(c)
+ end
+ i += 2
+ else if c == 'u' or c == 'U' then
+ var hx = substring(i + 1, 6)
+ if hx.is_hex then
+ res.add_char(hx.to_hex.code_point)
+ else
+ res.add_char(c)
+ end
+ i += 6
+ else
+ res.add_char(c)
+ end
+ i += 1
+ end
+ return res
+ end
+
+ # Return a `Bytes` by reading 0 and 1.
+ #
+ # assert "1010101100001101".binarydigest_to_bytes.hexdigest == "AB0D"
+ #
+ # Note that characters that are neither 0 or 1 are just ignored.
+ #
+ # assert "a1B01 010\n1100あ001101".binarydigest_to_bytes.hexdigest == "AB0D"
+ # assert "hello".binarydigest_to_bytes.is_empty
+ #
+ # When the number of bits is not divisible by 8, then leading 0 are
+ # implicitly considered to fill the left byte (the most significant one).
+ #
+ # assert "1".binarydigest_to_bytes.hexdigest == "01"
+ # assert "1111111".binarydigest_to_bytes.hexdigest == "7F"
+ # assert "1000110100".binarydigest_to_bytes.hexdigest == "0234"
+ #
+ # `Bytes::binarydigest` is a loosely reverse method since its
+ # results contain only 1 and 0 by blocks of 8.
+ #
+ # assert "1010101100001101".binarydigest_to_bytes.binarydigest == "1010101100001101"
+ # assert "1".binarydigest_to_bytes.binarydigest == "00000001"
+ fun binarydigest_to_bytes: Bytes
+ do
+ var b = bytes
+ var max = byte_length
+
+ # Count bits
+ var bitlen = 0
+ var pos = 0
+ while pos < max do
+ var c = b[pos]
+ pos += 1
+ if c == 0x30u8 or c == 0x31u8 then bitlen += 1 # b'0' or b'1'
+ end
+
+ # Allocate (and take care of the padding)
+ var ret = new Bytes.with_capacity((bitlen+7) / 8)
+
+ var i = (bitlen+7) % 8 # current bit (7th=128, 0th=1)
+ var byte = 0u8 # current accumulated byte value
+
+ pos = 0
+ while pos < max do
+ var c = b[pos]
+ pos += 1
+ if c == 0x30u8 then # b'0'
+ byte = byte << 1
+ else if c == 0x31u8 then # b'1'
+ byte = byte << 1 | 1u8
+ else
+ continue
+ end
+
+ i -= 1
+ if i < 0 then
+ # Last bit known: store and restart
+ ret.add byte
+ i = 7
+ byte = 0u8
+ end
+ end
+ return ret