1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Services for byte streams and arrays
19 import collection
::array
20 intrude import text
::flat
22 # Any kind of entity which can be searched for in a Sequence of Byte
24 # Return the first occurence of `self` in `b`, or -1 if not found
25 fun first_index_in
(b
: SequenceRead[Int]): Int do return first_index_in_from
(b
, 0)
27 # Return the first occurence of `self` in `b` starting at `from`, or -1 if not found
28 fun first_index_in_from
(b
: SequenceRead[Int], from
: Int): Int is abstract
30 # Return the last occurence of `self` in `b`, or -1 if not found
31 fun last_index_in
(b
: SequenceRead[Int]): Int do return last_index_in_from
(b
, b
.length
- 1)
33 # Return the last occurence of `self` in `b`, or -1 if not found
34 fun last_index_in_from
(b
: SequenceRead[Int], from
: Int): Int is abstract
36 # Returns the indexes of all the occurences of `self` in `b`
37 fun search_all_in
(b
: SequenceRead[Int]): SequenceRead[Int] is abstract
39 # Length of the pattern
40 fun pattern_length
: Int is abstract
42 # Appends `self` to `b`
43 fun append_to
(b
: Sequence[Int]) is abstract
45 # Is `self` a prefix for `b` ?
46 fun is_prefix
(b
: SequenceRead[Int]): Bool is abstract
48 # Is `self` a suffix for `b` ?
49 fun is_suffix
(b
: SequenceRead[Int]): Bool is abstract
55 # Write self as a string into `ns` at position `pos`
56 private fun add_digest_at
(ns
: CString, pos
: Int) do
57 var tmp
= (0xF0 & self) >> 4
58 ns
[pos
] = if tmp
>= 0x0A then tmp
+ 0x37 else tmp
+ 0x30
60 ns
[pos
+ 1] = if tmp
>= 0x0A then tmp
+ 0x37 else tmp
+ 0x30
63 # Is `self` a valid hexadecimal digit (in ASCII)
66 # intrude import core::bytes
67 # assert not u'/'.is_valid_hexdigit
68 # assert u'0'.is_valid_hexdigit
69 # assert u'9'.is_valid_hexdigit
70 # assert not u':'.is_valid_hexdigit
71 # assert not u'@'.is_valid_hexdigit
72 # assert u'A'.is_valid_hexdigit
73 # assert u'F'.is_valid_hexdigit
74 # assert not u'G'.is_valid_hexdigit
75 # assert not u'`'.is_valid_hexdigit
76 # assert u'a'.is_valid_hexdigit
77 # assert u'f'.is_valid_hexdigit
78 # assert not u'g'.is_valid_hexdigit
80 private fun is_valid_hexdigit
: Bool do
81 return (self >= 0x30 and self <= 0x39) or
82 (self >= 0x41 and self <= 0x46) or
83 (self >= 0x61 and self <= 0x66)
86 # `self` as a hexdigit to its byte value
89 # intrude import core::bytes
90 # assert 0x39.hexdigit_to_byteval == 0x09
91 # assert 0x43.hexdigit_to_byteval == 0x0C
94 # REQUIRE: `self.is_valid_hexdigit`
95 private fun hexdigit_to_byteval
: Int do
96 if self >= 0x30 and self <= 0x39 then
98 else if self >= 0x41 and self <= 0x46 then
100 else if self >= 0x61 and self <= 0x66 then
103 # Happens only if the requirement is not met.
104 # i.e. this abort is here to please the compiler
108 redef fun first_index_in_from
(b
, from
) do
109 for i
in [from
.. b
.length
[ do if b
[i
] == self then return i
113 redef fun last_index_in_from
(b
, from
) do
114 for i
in [0 .. from
].step
(-1) do if b
[i
] == self then return i
118 redef fun search_all_in
(b
) do
119 var ret
= new Array[Int]
122 pos
= first_index_in_from
(b
, pos
)
123 if pos
== -1 then return ret
129 redef fun pattern_length
do return 1
131 redef fun append_to
(b
) do b
.push
self
133 # assert u'b'.is_suffix("baqsdb".to_bytes)
134 # assert not u'b'.is_suffix("baqsd".to_bytes)
135 redef fun is_suffix
(b
) do return b
.length
!= 0 and b
.last
== self
137 # assert u'b'.is_prefix("baqsdb".to_bytes)
138 # assert not u'b'.is_prefix("aqsdb".to_bytes)
139 redef fun is_prefix
(b
) do return b
.length
!= 0 and b
.first
== self
141 # A signed big-endian representation of `self`
144 # assert 1.to_bytes.hexdigest == "01"
145 # assert 255.to_bytes.hexdigest == "FF"
146 # assert 256.to_bytes.hexdigest == "0100"
147 # assert 65535.to_bytes.hexdigest == "FFFF"
148 # assert 65536.to_bytes.hexdigest == "010000"
151 # Negative values are converted to their two's complement.
152 # Be careful as the result can be ambiguous.
155 # assert (-1).to_bytes.hexdigest == "FF"
156 # assert (-32).to_bytes.hexdigest == "E0"
157 # assert (-512).to_bytes.hexdigest == "FE00"
158 # assert (-65794).to_bytes.hexdigest == "FEFEFE"
161 # Optionally, set `n_bytes` to the desired number of bytes in the output.
162 # This setting can disambiguate the result between positive and negative
163 # integers. Be careful with this parameter as the result may overflow.
166 # assert 1.to_bytes(2).hexdigest == "0001"
167 # assert 65535.to_bytes(2).hexdigest == "FFFF"
168 # assert (-1).to_bytes(2).hexdigest == "FFFF"
169 # assert (-512).to_bytes(4).hexdigest == "FFFFFE00"
170 # assert 0x123456.to_bytes(2).hexdigest == "3456"
173 # For 0, a Bytes object with single nul byte is returned (instead of an empty Bytes object).
176 # assert 0.to_bytes.hexdigest == "00"
179 # For positive integers, `Bytes::to_i` can reverse the operation.
182 # assert 1234.to_bytes.to_i == 1234
186 fun to_bytes
(n_bytes
: nullable Int): Bytes do
188 # If 0, force using at least one byte
189 if self == 0 and n_bytes
== null then n_bytes
= 1
191 # Compute the len (log256)
209 s
= ((-self) ^ ff
) + 1
213 if n_bytes
!= null and len
> n_bytes
then len
= n_bytes
215 # Allocate the buffer
216 var cap
= n_bytes
or else len
217 var res
= new Bytes.with_capacity
(cap
)
219 var filler
= if self < 0 then 0xFF else 0
220 for i
in [0..cap
[ do res
[i
] = filler
222 # Fill it starting with the end
225 while i
> cap
- len
do
235 # A buffer containing Byte-manipulation facilities
237 # Uses Copy-On-Write when persisted
239 super AbstractArray[Int]
242 # A CString being a char*, it can be used as underlying representation here.
245 # Number of bytes in the array
248 # Capacity of the array
249 private var capacity
: Int
251 # Has this buffer been persisted (to_s'd)?
253 # Used for Copy-On-Write
254 private var persisted
= false
256 # var b = new Bytes.empty
257 # assert b.to_s == ""
259 var ns
= new CString(0)
263 # Init a `Bytes` with capacity `cap`
264 init with_capacity
(cap
: Int) do
265 var ns
= new CString(cap
)
269 redef fun pattern_length
do return length
271 redef fun is_empty
do return length
== 0
273 # var b = new Bytes.empty
282 # Returns a copy of `self`
284 var b
= new Bytes.with_capacity
(length
)
289 # Trims off the whitespaces at the beginning and the end of `self`
291 # var b = "102041426E6F1020" .hexdigest_to_bytes
292 # assert b.trim.hexdigest == "41426E6F"
294 # NOTE: A whitespace is defined here as a byte whose value is <= 0x20
298 if self[st
] > 0x20 then break
301 if st
>= length
then return new Bytes.empty
304 if self[ed
] > 0x20 then break
307 return slice
(st
, ed
- st
+ 1)
310 # Copy a subset of `self` starting at `from` and of `count` bytes
312 # var b = "abcd".to_bytes
313 # assert b.slice(1, 2).hexdigest == "6263"
314 # assert b.slice(-1, 2).hexdigest == "61"
315 # assert b.slice(1, 0).hexdigest == ""
316 # assert b.slice(2, 5).hexdigest == "6364"
317 fun slice
(from
, count
: Int): Bytes do
318 if count
<= 0 then return new Bytes.empty
322 if count
< 0 then count
= 0
326 if (count
+ from
) > length
then count
= length
- from
327 if count
<= 0 then return new Bytes.empty
329 var ret
= new Bytes.with_capacity
(count
)
331 ret
.append_ns
(items
.fast_cstring
(from
), count
)
335 # Copy of `self` starting at `from`
337 # var b = "abcd".to_bytes
338 # assert b.slice_from(1).hexdigest == "626364"
339 # assert b.slice_from(-1).hexdigest == "61626364"
340 # assert b.slice_from(2).hexdigest == "6364"
341 fun slice_from
(from
: Int): Bytes do
342 if from
>= length
then return new Bytes.empty
343 if from
< 0 then from
= 0
344 return slice
(from
, length
)
347 # Reverse the byte array in place
349 # var b = "abcd".to_bytes
351 # assert b.to_s == "dcba"
357 self[i
] = self[l-i-1
]
362 # Returns self as an hexadecimal digest.
364 # Also known as plain hexdump or postscript hexdump.
367 # var b = "abcd".to_bytes
368 # assert b.hexdigest == "61626364"
369 # assert b.hexdigest.hexdigest_to_bytes == b
371 fun hexdigest
: String do
372 var elen
= length
* 2
373 var ns
= new CString(elen
)
377 self[i
].add_digest_at
(ns
, oi
)
381 return new FlatString.full
(ns
, elen
, 0, elen
)
384 # Return self as a C hexadecimal digest where bytes are prefixed by `\x`
386 # The output is compatible with literal stream of bytes for most languages
387 # including C and Nit.
390 # var b = "abcd".to_bytes
391 # assert b.chexdigest == "\\x61\\x62\\x63\\x64"
392 # assert b.chexdigest.unescape_to_bytes == b
394 fun chexdigest
: String do
395 var elen
= length
* 4
396 var ns
= new CString(elen
)
402 self[i
].add_digest_at
(ns
, oi
+2)
406 return new FlatString.full
(ns
, elen
, 0, elen
)
410 # Returns self as a stream of bits (0 and 1)
413 # var b = "abcd".to_bytes
414 # assert b.binarydigest == "01100001011000100110001101100100"
415 # assert b.binarydigest.binarydigest_to_bytes == b
417 fun binarydigest
: String do
418 var elen
= length
* 8
419 var ns
= new CString(elen
)
436 return new FlatString.full
(ns
, elen
, 0, elen
)
439 # Interprets `self` as a big-endian integer (unsigned by default)
442 # var b = "0102".hexdigest_to_bytes
443 # assert b.to_i == 258
445 # assert "01".hexdigest_to_bytes.to_i == 1
446 # assert "FF".hexdigest_to_bytes.to_i == 255
447 # assert "0000".hexdigest_to_bytes.to_i == 0
450 # If `self.is_empty`, 0 is returned.
453 # assert "".hexdigest_to_bytes.to_i == 0
456 # If `signed == true`, the bytes are read as a signed integer.
457 # As usual, the sign bit is the left most bit, no matter the
458 # `length` of `self`.
461 # assert "01".hexdigest_to_bytes.to_i(true) == 1
462 # assert "FF".hexdigest_to_bytes.to_i(true) == -1
463 # assert "00FF".hexdigest_to_bytes.to_i(true) == 255
464 # assert "E0".hexdigest_to_bytes.to_i(true) == -32
465 # assert "FE00".hexdigest_to_bytes.to_i(true) == -512
466 # assert "FEFEFE".hexdigest_to_bytes.to_i(true) == -65794
469 # `Int::to_bytes` is a loosely reverse method.
472 # assert b.to_i.to_bytes == b
473 # assert (b.to_i + 1).to_bytes.hexdigest == "0103"
474 # assert "0001".hexdigest_to_bytes.to_i.to_bytes.hexdigest == "01"
476 # assert (-32).to_bytes.to_i(true) == -32
479 # Warning: `Int` might overflow for bytes with more than 60 bits.
480 fun to_i
(signed
: nullable Bool): Int do
489 # Two's complement is `signed`
490 if signed
== true and not_empty
and first
> 0x80 then
492 for j
in [0..length
[ do
497 res
= -((res ^ ff
) + 1)
503 # var b = new Bytes.with_capacity(1)
505 # assert b.to_s == "e"
506 redef fun []=(i
, v
) do
507 if persisted
then regen
510 if i
== length
then add
(v
)
514 # var b = new Bytes.empty
516 # assert b.to_s == "e"
518 if persisted
then regen
519 if length
>= capacity
then
526 # Adds the UTF-8 representation of `c` to `self`
528 # var b = new Bytes.empty
531 # assert b.hexdigest == "41E382AD"
532 fun add_char
(c
: Char) do
533 if persisted
then regen
534 var cln
= c
.u8char_len
537 items
.set_char_at
(length
, c
)
543 if not c
isa Int then return false
547 # var b = new Bytes.empty
548 # b.append([104, 101, 108, 108, 111])
549 # assert b.to_s == "hello"
550 redef fun append
(arr
) do
551 if arr
isa Bytes then
552 append_ns
(arr
.items
, arr
.length
)
554 for i
in arr
do add i
558 # var b = new Bytes.empty
559 # b.append([0x41, 0x41, 0x18])
561 # assert b.to_s == "AA"
568 redef fun clear
do length
= 0
570 # Regenerates the buffer, necessary when it was persisted
572 var nns
= new CString(capacity
)
573 items
.copy_to
(nns
, length
, 0, 0)
577 # Appends the `ln` first bytes of `ns` to self
578 fun append_ns
(ns
: CString, ln
: Int) do
579 if persisted
then regen
580 var nlen
= length
+ ln
581 if nlen
> capacity
then enlarge
(nlen
)
582 ns
.copy_to
(items
, ln
, 0, length
)
586 # Appends `ln` bytes from `ns` starting at index `from` to self
587 fun append_ns_from
(ns
: CString, ln
, from
: Int) do
588 if persisted
then regen
589 var nlen
= length
+ ln
590 if nlen
> capacity
then enlarge
(nlen
)
591 ns
.copy_to
(items
, ln
, from
, length
)
595 # Appends the bytes of `str` to `self`
596 fun append_text
(str
: Text) do str
.append_to_bytes
self
598 redef fun append_to
(b
) do b
.append
self
600 redef fun enlarge
(sz
) do
601 if capacity
>= sz
then return
603 if capacity
< 16 then capacity
= 16
604 while capacity
< sz
do capacity
= capacity
* 2 + 2
605 var ns
= new CString(capacity
)
606 items
.copy_to
(ns
, length
, 0, 0)
613 var r
= b
.items
.to_s_unsafe
(length
, copy
=false)
614 if r
!= items
then persisted
= false
618 redef fun iterator
do return new BytesIterator.with_buffer
(self)
620 redef fun first_index_in_from
(b
, from
) do
621 if is_empty
then return -1
623 var bpos
= fst
.first_index_in_from
(self, from
)
624 for i
in [0 .. length
[ do
625 if self[i
] != b
[bpos
] then return first_index_in_from
(b
, bpos
+ 1)
631 redef fun last_index_in_from
(b
, from
) do
632 if is_empty
then return -1
633 var lst
= self[length
- 1]
634 var bpos
= lst
.last_index_in_from
(b
, from
)
635 for i
in [0 .. length
[.step
(-1) do
636 if self[i
] != b
[bpos
] then return last_index_in_from
(b
, bpos
- 1)
642 redef fun search_all_in
(b
) do
643 var ret
= new Array[Int]
644 var pos
= first_index_in_from
(b
, 0)
645 if pos
== -1 then return ret
649 pos
= first_index_in_from
(b
, pos
)
650 if pos
== -1 then return ret
656 # Splits the content on self when encountering `b`
658 # var a = "String is string".to_bytes.split_with(u's')
659 # assert a.length == 3
660 # assert a[0].hexdigest == "537472696E672069"
661 # assert a[1].hexdigest == "20"
662 # assert a[2].hexdigest == "7472696E67"
663 fun split_with
(b
: BytePattern): Array[Bytes] do
664 var fst
= b
.search_all_in
(self)
665 if fst
.is_empty
then return [clone
]
666 var retarr
= new Array[Bytes]
669 retarr
.add
(slice
(prev
, i
- prev
))
670 prev
= i
+ b
.pattern_length
672 retarr
.add slice_from
(prev
)
676 # Splits `self` in two parts at the first occurence of `b`
678 # var a = "String is string".to_bytes.split_once_on(u's')
679 # assert a[0].hexdigest == "537472696E672069"
680 # assert a[1].hexdigest == "20737472696E67"
681 fun split_once_on
(b
: BytePattern): Array[Bytes] do
682 var spl
= b
.first_index_in
(self)
683 if spl
== -1 then return [clone
]
684 var ret
= new Array[Bytes].with_capacity
(2)
685 ret
.add
(slice
(0, spl
))
686 ret
.add
(slice_from
(spl
+ b
.pattern_length
))
690 # Replaces all the occurences of `this` in `self` by `by`
692 # var b = "String is string".to_bytes.replace(0x20, 0x41)
693 # assert b.hexdigest == "537472696E6741697341737472696E67"
694 fun replace
(pattern
: BytePattern, bytes
: BytePattern): Bytes do
695 if is_empty
then return new Bytes.empty
696 var pos
= pattern
.search_all_in
(self)
697 if pos
.is_empty
then return clone
698 var ret
= new Bytes.with_capacity
(length
)
701 ret
.append_ns
(items
.fast_cstring
(prev
), i
- prev
)
703 prev
= i
+ pattern
.pattern_length
705 ret
.append
(slice_from
(pos
.last
+ pattern
.pattern_length
))
709 # Decode `self` from percent (or URL) encoding to a clear string
711 # Invalid '%' are not decoded.
713 # assert "aBc09-._~".to_bytes.from_percent_encoding == "aBc09-._~".to_bytes
714 # assert "%25%28%29%3c%20%3e".to_bytes.from_percent_encoding == "%()< >".to_bytes
715 # assert ".com%2fpost%3fe%3dasdf%26f%3d123".to_bytes.from_percent_encoding == ".com/post?e=asdf&f=123".to_bytes
716 # assert "%25%28%29%3C%20%3E".to_bytes.from_percent_encoding == "%()< >".to_bytes
717 # assert "incomplete %".to_bytes.from_percent_encoding == "incomplete %".to_bytes
718 # assert "invalid % usage".to_bytes.from_percent_encoding == "invalid % usage".to_bytes
719 # assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".to_bytes.from_percent_encoding == "éあいう".to_bytes
720 # assert "%1 %A %C3%A9A9".to_bytes.from_percent_encoding == "%1 %A éA9".to_bytes
721 fun from_percent_encoding
: Bytes do
722 var tmp
= new Bytes.with_capacity
(length
)
724 while pos
< length
do
731 if length
- pos
< 2 then
736 var bn
= self[pos
+ 1]
737 var bnn
= self[pos
+ 2]
738 if not bn
.is_valid_hexdigit
or not bnn
.is_valid_hexdigit
then
743 tmp
.add
((bn
.hexdigit_to_byteval
<< 4) + bnn
.hexdigit_to_byteval
)
749 # Is `b` a prefix of `self` ?
750 fun has_prefix
(b
: BytePattern): Bool do return b
.is_prefix
(self)
752 # Is `b` a suffix of `self` ?
753 fun has_suffix
(b
: BytePattern): Bool do return b
.is_suffix
(self)
755 redef fun is_suffix
(b
) do
756 if length
> b
.length
then return false
760 if self[i
] != b
[j
] then return false
767 redef fun is_prefix
(b
) do
768 if length
> b
.length
then return false
769 for i
in [0 .. length
[ do if self[i
] != b
[i
] then return false
774 private class BytesIterator
775 super IndexedIterator[Int]
783 init with_buffer
(b
: Bytes) do init(b
.items
, 0, b
.length
)
785 redef fun is_ok
do return index
< max
787 redef fun next
do index
+= 1
789 redef fun item
do return tgt
[index
]
793 # Returns a mutable copy of `self`'s bytes
796 # assert "String".to_bytes isa Bytes
797 # assert "String".to_bytes == [83, 116, 114, 105, 110, 103]
799 fun to_bytes
: Bytes do
800 var b
= new Bytes.with_capacity
(byte_length
)
805 # Is `self` a valid hexdigest ?
807 # assert "0B1d3F".is_valid_hexdigest
808 # assert not "5G".is_valid_hexdigest
809 fun is_valid_hexdigest
: Bool do
810 for i
in bytes
do if not i
.is_valid_hexdigit
then return false
814 # Appends `self.bytes` to `b`
815 fun append_to_bytes
(b
: Bytes) do
816 for s
in substrings
do
817 var from
= if s
isa FlatString then s
.first_byte
else 0
818 b
.append_ns_from
(s
.items
, s
.byte_length
, from
)
822 # Returns a new `Bytes` instance with the digest as content
824 # assert "0B1F4D".hexdigest_to_bytes == [0x0B, 0x1F, 0x4D]
825 # assert "0B1F4D".hexdigest_to_bytes.hexdigest == "0B1F4D"
827 # Characters that are not hexadecimal digits are ignored.
829 # assert "z0B1 F4\nD".hexdigest_to_bytes.hexdigest == "0B1F4D"
830 # assert "\\x0b1 \\xf4d".hexdigest_to_bytes.hexdigest == "0B1F4D"
832 # When the number of hexadecimal digit is not even, then a leading 0 is
833 # implicitly considered to fill the left byte (the most significant one).
835 # assert "1".hexdigest_to_bytes.hexdigest == "01"
836 # assert "FFF".hexdigest_to_bytes.hexdigest == "0FFF"
838 # `Bytes::hexdigest` is a loosely reverse method since its
839 # results contain only pairs of uppercase hexadecimal digits.
841 # assert "ABCD".hexdigest_to_bytes.hexdigest == "ABCD"
842 # assert "a b c".hexdigest_to_bytes.hexdigest == "0ABC"
843 fun hexdigest_to_bytes
: Bytes do
845 var max
= byte_length
847 var dlength
= 0 # Number of hex digits
851 if c
.is_valid_hexdigit
then dlength
+= 1
855 # Allocate the result buffer
856 var ret
= new Bytes.with_capacity
((dlength
+1) / 2)
858 var i
= (dlength
+1) % 2 # current hex digit (1=high, 0=low)
859 var byte
= 0 # current accumulated byte value
864 if c
.is_valid_hexdigit
then
865 byte
= byte
<< 4 | c
.hexdigit_to_byteval
868 # Last digit known: store and restart
879 # Gets the hexdigest of the bytes of `self`
881 # assert "<STRING/&rt;".hexdigest == "266C743B535452494E47262334373B2672743B"
882 fun hexdigest
: String do
884 var outns
= new CString(ln
* 2)
886 for i
in [0 .. ln
[ do
887 bytes
[i
].add_digest_at
(outns
, oi
)
890 return new FlatString.with_infos
(outns
, ln
* 2, 0)
893 # Return a `Bytes` instance where Nit escape sequences are transformed.
895 # assert "B\\n\\x41\\u0103D3".unescape_to_bytes.hexdigest == "420A41F0908F93"
897 # `Bytes::chexdigest` is a loosely reverse methods since its result is only made
898 # of `"\x??"` escape sequences.
900 # assert "\\x41\\x42\\x43".unescape_to_bytes.chexdigest == "\\x41\\x42\\x43"
901 # assert "B\\n\\x41\\u0103D3".unescape_to_bytes.chexdigest == "\\x42\\x0A\\x41\\xF0\\x90\\x8F\\x93"
902 fun unescape_to_bytes
: Bytes do
903 var res
= new Bytes.with_capacity
(self.byte_length
)
904 var was_slash
= false
908 if not was_slash
then
920 else if c
== 'r' then
922 else if c
== 't' then
924 else if c
== '0' then
926 else if c
== 'x' or c
== 'X' then
927 var hx
= substring
(i
+ 1, 2)
934 else if c
== 'u' or c
== 'U' then
935 var hx
= substring
(i
+ 1, 6)
937 res
.add_char
(hx
.to_hex
.code_point
)
950 # Return a `Bytes` by reading 0 and 1.
952 # assert "1010101100001101".binarydigest_to_bytes.hexdigest == "AB0D"
954 # Note that characters that are neither 0 or 1 are just ignored.
956 # assert "a1B01 010\n1100あ001101".binarydigest_to_bytes.hexdigest == "AB0D"
957 # assert "hello".binarydigest_to_bytes.is_empty
959 # When the number of bits is not divisible by 8, then leading 0 are
960 # implicitly considered to fill the left byte (the most significant one).
962 # assert "1".binarydigest_to_bytes.hexdigest == "01"
963 # assert "1111111".binarydigest_to_bytes.hexdigest == "7F"
964 # assert "1000110100".binarydigest_to_bytes.hexdigest == "0234"
966 # `Bytes::binarydigest` is a loosely reverse method since its
967 # results contain only 1 and 0 by blocks of 8.
969 # assert "1010101100001101".binarydigest_to_bytes.binarydigest == "1010101100001101"
970 # assert "1".binarydigest_to_bytes.binarydigest == "00000001"
971 fun binarydigest_to_bytes
: Bytes
974 var max
= byte_length
982 if c
== u
'0' or c
== u
'1' then bitlen
+= 1
985 # Allocate (and take care of the padding)
986 var ret
= new Bytes.with_capacity
((bitlen
+7) / 8)
988 var i
= (bitlen
+7) % 8 # current bit (7th=128, 0th=1)
989 var byte
= 0 # current accumulated byte value
997 else if c
== u
'1' then
1005 # Last bit known: store and restart
1015 redef class FlatText
1016 redef fun append_to_bytes
(b
) do
1017 var from
= if self isa FlatString then first_byte
else 0
1018 if isset _items
then b
.append_ns_from
(items
, byte_length
, from
)
1023 # Creates a new `Bytes` object from `self` with `len` as length
1025 # If `len` is null, strlen will determine the length of the Bytes
1026 fun to_bytes
(len
: nullable Int): Bytes do
1027 if len
== null then len
= cstring_length
1028 return new Bytes(self, len
, len
)
1031 # Creates a new `Bytes` object from a copy of `self` with `len` as length
1033 # If `len` is null, strlen will determine the length of the Bytes
1034 fun to_bytes_with_copy
(len
: nullable Int): Bytes do
1035 if len
== null then len
= cstring_length
1036 var nns
= new CString(len
)
1037 copy_to
(nns
, len
, 0, 0)
1038 return new Bytes(nns
, len
, len
)
1042 # Joins an array of bytes `arr` separated by `sep`
1044 # assert join_bytes(["String".to_bytes, "is".to_bytes, "string".to_bytes], u' ').hexdigest == "537472696E6720697320737472696E67"
1045 fun join_bytes
(arr
: Array[Bytes], sep
: nullable BytePattern): Bytes do
1046 if arr
.is_empty
then return new Bytes.empty
1047 sep
= sep
or else new Bytes.empty
1048 var endln
= sep
.pattern_length
* (arr
.length
- 1)
1049 for i
in arr
do endln
+= i
.length
1050 var ret
= new Bytes.with_capacity
(endln
)
1051 ret
.append
(arr
.first
)
1052 for i
in [1 .. arr
.length
[ do