mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-15 15:44:04 +00:00
Fix #6229
Fixes #6229 by adding `encode_upper` and `encode_upper_into_writer`. Also updated the documentation to be more like the rest of `core`.
This commit is contained in:
@@ -1,35 +1,115 @@
|
||||
// Encoding and decoding of hex-encoded binary, e.g. `0x23` -> `#`.
|
||||
package encoding_hex
|
||||
|
||||
import "base:runtime"
|
||||
import "core:io"
|
||||
import "core:strings"
|
||||
|
||||
encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> []byte #no_bounds_check {
|
||||
dst := make([]byte, len(src) * 2, allocator, loc)
|
||||
for i, j := 0, 0; i < len(src); i += 1 {
|
||||
/*
|
||||
Encodes a byte slice into a lowercase hex sequence
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
Inputs:
|
||||
- src: The `[]byte` to be hex-encoded
|
||||
- allocator: (default: context.allocator)
|
||||
- loc: The caller location for debugging purposes (default: #caller_location)
|
||||
|
||||
Returns:
|
||||
- res: The hex-encoded result
|
||||
- err: An optional allocator error if one occured, `.None` otherwise
|
||||
*/
|
||||
encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) #optional_allocator_error {
|
||||
res, err = make([]byte, len(src) * 2, allocator, loc)
|
||||
#no_bounds_check for i, j := 0, 0; i < len(src); i += 1 {
|
||||
v := src[i]
|
||||
dst[j] = HEXTABLE[v>>4]
|
||||
dst[j+1] = HEXTABLE[v&0x0f]
|
||||
res[j] = LOWER[v>>4]
|
||||
res[j+1] = LOWER[v&0x0f]
|
||||
j += 2
|
||||
}
|
||||
|
||||
return dst
|
||||
return
|
||||
}
|
||||
|
||||
encode_into_writer :: proc(dst: io.Writer, src: []byte) -> io.Error {
|
||||
/*
|
||||
Encodes a byte slice as a lowercase hex sequence into an `io.Writer`
|
||||
|
||||
Inputs:
|
||||
- dst: The `io.Writer` to encode into
|
||||
- src: The `[]byte` to be hex-encoded
|
||||
|
||||
Returns:
|
||||
- err: An `io.Error` if one occured, `.None` otherwise
|
||||
*/
|
||||
encode_into_writer :: proc(dst: io.Writer, src: []byte) -> (err: io.Error) {
|
||||
for v in src {
|
||||
io.write(dst, {HEXTABLE[v>>4], HEXTABLE[v&0x0f]}) or_return
|
||||
io.write(dst, {LOWER[v>>4], LOWER[v&0x0f]}) or_return
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) #no_bounds_check {
|
||||
/*
|
||||
Encodes a byte slice into an uppercase hex sequence
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
Inputs:
|
||||
- src: The `[]byte` to be hex-encoded
|
||||
- allocator: (default: context.allocator)
|
||||
- loc: The caller location for debugging purposes (default: #caller_location)
|
||||
|
||||
Returns:
|
||||
- res: The hex-encoded result
|
||||
- err: An optional allocator error if one occured, `.None` otherwise
|
||||
*/
|
||||
encode_upper :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) #optional_allocator_error {
|
||||
res, err = make([]byte, len(src) * 2, allocator, loc)
|
||||
#no_bounds_check for i, j := 0, 0; i < len(src); i += 1 {
|
||||
v := src[i]
|
||||
res[j] = UPPER[v>>4]
|
||||
res[j+1] = UPPER[v&0x0f]
|
||||
j += 2
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Encodes a byte slice as an uppercase hex sequence into an `io.Writer`
|
||||
|
||||
Inputs:
|
||||
- dst: The `io.Writer` to encode into
|
||||
- src: The `[]byte` to be hex-encoded
|
||||
|
||||
Returns:
|
||||
- err: An `io.Error` if one occured, `.None` otherwise
|
||||
*/
|
||||
encode_upper_into_writer :: proc(dst: io.Writer, src: []byte) -> (err: io.Error) {
|
||||
for v in src {
|
||||
io.write(dst, {UPPER[v>>4], UPPER[v&0x0f]}) or_return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Decodes a hex sequence into a byte slice
|
||||
|
||||
*Allocates Using Provided Allocator*
|
||||
|
||||
Inputs:
|
||||
- dst: The hex sequence decoded into bytes
|
||||
- src: The `[]byte` to be hex-decoded
|
||||
- allocator: (default: context.allocator)
|
||||
- loc: The caller location for debugging purposes (default: #caller_location)
|
||||
|
||||
Returns:
|
||||
- ok: A bool, `true` if decoding succeeded, `false` otherwise
|
||||
*/
|
||||
decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) {
|
||||
if len(src) % 2 == 1 {
|
||||
return
|
||||
}
|
||||
|
||||
dst = make([]byte, len(src) / 2, allocator, loc)
|
||||
for i, j := 0, 1; j < len(src); j += 2 {
|
||||
#no_bounds_check for i, j := 0, 1; j < len(src); j += 2 {
|
||||
p := src[j-1]
|
||||
q := src[j]
|
||||
|
||||
@@ -43,8 +123,16 @@ decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_locat
|
||||
return dst, true
|
||||
}
|
||||
|
||||
// Decodes the given sequence into one byte.
|
||||
// Should be called with one byte worth of the source, eg: 0x23 -> '#'.
|
||||
/*
|
||||
Decodes the first byte in a hex sequence to a byte
|
||||
|
||||
Inputs:
|
||||
- str: A hex-encoded `string`, e.g. `"0x23"`
|
||||
|
||||
Returns:
|
||||
- res: The decoded byte, e.g. `'#'`
|
||||
- ok: A bool, `true` if decoding succeeded, `false` otherwise
|
||||
*/
|
||||
decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
|
||||
str := str
|
||||
if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") {
|
||||
@@ -62,13 +150,21 @@ decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
|
||||
}
|
||||
|
||||
@(private)
|
||||
HEXTABLE := [16]byte {
|
||||
LOWER := [16]byte {
|
||||
'0', '1', '2', '3',
|
||||
'4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b',
|
||||
'c', 'd', 'e', 'f',
|
||||
}
|
||||
|
||||
@(private)
|
||||
UPPER := [16]byte {
|
||||
'0', '1', '2', '3',
|
||||
'4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F',
|
||||
}
|
||||
|
||||
@(private)
|
||||
hex_digit :: proc(char: byte) -> (u8, bool) {
|
||||
switch char {
|
||||
|
||||
Reference in New Issue
Block a user