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
23 # Write self as a string into `ns` at position `pos`
24 private fun add_digest_at
(ns
: NativeString, pos
: Int) do
25 var tmp
= (0xF0u
8 & self) >> 4
26 ns
[pos
] = if tmp
>= 0x0Au
8 then tmp
+ 0x37u
8 else tmp
+ 0x30u
8
28 ns
[pos
+ 1] = if tmp
>= 0x0Au
8 then tmp
+ 0x37u
8 else tmp
+ 0x30u
8
31 # Is `self` a valid hexadecimal digit (in ASCII)
34 # intrude import core::bytes
35 # assert not '/'.ascii.is_valid_hexdigit
36 # assert '0'.ascii.is_valid_hexdigit
37 # assert '9'.ascii.is_valid_hexdigit
38 # assert not ':'.ascii.is_valid_hexdigit
39 # assert not '@'.ascii.is_valid_hexdigit
40 # assert 'A'.ascii.is_valid_hexdigit
41 # assert 'F'.ascii.is_valid_hexdigit
42 # assert not 'G'.ascii.is_valid_hexdigit
43 # assert not '`'.ascii.is_valid_hexdigit
44 # assert 'a'.ascii.is_valid_hexdigit
45 # assert 'f'.ascii.is_valid_hexdigit
46 # assert not 'g'.ascii.is_valid_hexdigit
48 private fun is_valid_hexdigit
: Bool do
49 return (self >= 0x30u
8 and self <= 0x39u
8) or
50 (self >= 0x41u
8 and self <= 0x46u
8) or
51 (self >= 0x61u
8 and self <= 0x66u
8)
54 # `self` as a hexdigit to its byte value
57 # intrude import core::bytes
58 # assert 0x39u8.hexdigit_to_byteval == 0x09u8
59 # assert 0x43u8.hexdigit_to_byteval == 0x0Cu8
62 # REQUIRE: `self.is_valid_hexdigit`
63 private fun hexdigit_to_byteval
: Byte do
64 if self >= 0x30u
8 and self <= 0x39u
8 then
66 else if self >= 0x41u
8 and self <= 0x46u
8 then
68 else if self >= 0x61u
8 and self <= 0x66u
8 then
71 # Happens only if the requirement is not met.
72 # i.e. this abort is here to please the compiler
77 # A buffer containing Byte-manipulation facilities
79 # Uses Copy-On-Write when persisted
81 super AbstractArray[Byte]
83 # A NativeString being a char*, it can be used as underlying representation here.
84 var items
: NativeString
86 # Number of bytes in the array
89 # Capacity of the array
90 private var capacity
: Int
92 # Has this buffer been persisted (to_s'd)?
94 # Used for Copy-On-Write
95 private var persisted
= false
97 # var b = new Bytes.empty
100 var ns
= new NativeString(0)
104 # Init a `Bytes` with capacity `cap`
105 init with_capacity
(cap
: Int) do
106 var ns
= new NativeString(cap
)
110 redef fun is_empty
do return length
!= 0
112 # var b = new Bytes.empty
114 # assert b[0] == 101u8
121 # Returns self as a hexadecimal digest
122 fun hexdigest
: String do
123 var elen
= length
* 2
124 var ns
= new NativeString(elen
)
128 self[i
].add_digest_at
(ns
, oi
)
132 return new FlatString.full
(ns
, elen
, 0, elen
- 1, elen
)
135 # var b = new Bytes.with_capacity(1)
137 # assert b.to_s == "e"
138 redef fun []=(i
, v
) do
139 if persisted
then regen
142 if i
== length
then add
(v
)
146 # var b = new Bytes.empty
148 # assert b.to_s == "e"
150 if persisted
then regen
151 if length
>= capacity
then
158 # var b = new Bytes.empty
159 # b.append([104u8, 101u8, 108u8, 108u8, 111u8])
160 # assert b.to_s == "hello"
161 redef fun append
(arr
) do
162 if arr
isa Bytes then
163 append_ns
(arr
.items
, arr
.length
)
165 for i
in arr
do add i
169 # var b = new Bytes.empty
170 # b.append([0x41u8, 0x41u8, 0x18u8])
172 # assert b.to_s == "AA"
179 redef fun clear
do length
= 0
181 # Regenerates the buffer, necessary when it was persisted
183 var nns
= new NativeString(capacity
)
184 items
.copy_to
(nns
, length
, 0, 0)
188 # Appends the `ln` first bytes of `ns` to self
189 fun append_ns
(ns
: NativeString, ln
: Int) do
190 if persisted
then regen
191 var nlen
= length
+ ln
192 if nlen
> capacity
then enlarge
(nlen
)
193 ns
.copy_to
(items
, ln
, 0, length
)
197 # Appends `ln` bytes from `ns` starting at index `from` to self
198 fun append_ns_from
(ns
: NativeString, ln
, from
: Int) do
199 if persisted
then regen
200 var nlen
= length
+ ln
201 if nlen
> capacity
then enlarge
(nlen
)
202 ns
.copy_to
(items
, ln
, from
, length
)
206 redef fun enlarge
(sz
) do
207 if capacity
>= sz
then return
209 while capacity
< sz
do capacity
= capacity
* 2 + 2
210 var ns
= new NativeString(capacity
)
211 items
.copy_to
(ns
, length
, 0, 0)
218 var r
= b
.items
.to_s_with_length
(length
)
219 if r
!= items
then persisted
= false
223 redef fun iterator
do return new BytesIterator.with_buffer
(self)
227 private class BytesIterator
228 super IndexedIterator[Byte]
230 var tgt
: NativeString
236 init with_buffer
(b
: Bytes) do init(b
.items
, 0, b
.length
)
238 redef fun is_ok
do return index
< max
240 redef fun next
do index
+= 1
242 redef fun item
do return tgt
[index
]
246 # Returns a mutable copy of `self`'s bytes
249 # assert "String".to_bytes isa Bytes
250 # assert "String".to_bytes == [83u8, 116u8, 114u8, 105u8, 110u8, 103u8]
252 fun to_bytes
: Bytes do
253 var b
= new Bytes.with_capacity
(bytelen
)
258 # Is `self` a valid hexdigest ?
260 # assert "0B1d3F".is_valid_hexdigest
261 # assert not "5G".is_valid_hexdigest
262 fun is_valid_hexdigest
: Bool do
263 for i
in bytes
do if not i
.is_valid_hexdigit
then return false
267 # Appends `self.bytes` to `b`
268 fun append_to_bytes
(b
: Bytes) do
269 for s
in substrings
do
270 var from
= if s
isa FlatString then s
.first_byte
else 0
271 b
.append_ns_from
(s
.items
, s
.bytelen
, from
)
275 # Returns a new `Bytes` instance with the digest as content
277 # assert "0B1F4D".hexdigest_to_bytes == [0x0Bu8, 0x1Fu8, 0x4Du8]
279 # REQUIRE: `self` is a valid hexdigest and hexdigest.length % 2 == 0
280 fun hexdigest_to_bytes
: Bytes do
284 var ret
= new Bytes.with_capacity
(max
/ 2)
286 ret
.add
((b
[pos
].hexdigit_to_byteval
<< 4) |
287 b
[pos
+ 1].hexdigit_to_byteval
)
293 # Gets the hexdigest of the bytes of `self`
295 # assert "<STRING/&rt;".hexdigest == "266C743B535452494E47262334373B2672743B"
296 fun hexdigest
: String do
298 var outns
= new NativeString(ln
* 2)
300 for i
in [0 .. ln
[ do
301 bytes
[i
].add_digest_at
(outns
, oi
)
304 return new FlatString.with_infos
(outns
, ln
* 2, 0, ln
* 2 - 1)
309 redef fun append_to_bytes
(b
) do
310 var from
= if self isa FlatString then first_byte
else 0
311 b
.append_ns_from
(items
, bytelen
, from
)
315 redef class NativeString
316 # Creates a new `Bytes` object from `self` with `strlen` as length
317 fun to_bytes
: Bytes do
318 var len
= cstring_length
319 return new Bytes(self, len
, len
)