hex.odin 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package hex
  2. import "core:strings"
  3. encode :: proc(src: []byte, allocator := context.allocator) -> []byte #no_bounds_check {
  4. dst := make([]byte, len(src) * 2, allocator)
  5. for i, j := 0, 0; i < len(src); i += 1 {
  6. v := src[i]
  7. dst[j] = HEXTABLE[v>>4]
  8. dst[j+1] = HEXTABLE[v&0x0f]
  9. j += 2
  10. }
  11. return dst
  12. }
  13. decode :: proc(src: []byte, allocator := context.allocator) -> (dst: []byte, ok: bool) #no_bounds_check {
  14. if len(src) % 2 == 1 {
  15. return
  16. }
  17. dst = make([]byte, len(src) / 2, allocator)
  18. for i, j := 0, 1; j < len(src); j += 2 {
  19. p := src[j-1]
  20. q := src[j]
  21. a := hex_digit(p) or_return
  22. b := hex_digit(q) or_return
  23. dst[i] = (a << 4) | b
  24. i += 1
  25. }
  26. return dst, true
  27. }
  28. // Decodes the given sequence into one byte.
  29. // Should be called with one byte worth of the source, eg: 0x23 -> '#'.
  30. decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
  31. str := str
  32. if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") {
  33. str = str[2:]
  34. }
  35. if len(str) != 2 {
  36. return 0, false
  37. }
  38. upper := hex_digit(str[0]) or_return
  39. lower := hex_digit(str[1]) or_return
  40. return upper << 4 | lower, true
  41. }
  42. @(private)
  43. HEXTABLE := [16]byte {
  44. '0', '1', '2', '3',
  45. '4', '5', '6', '7',
  46. '8', '9', 'a', 'b',
  47. 'c', 'd', 'e', 'f',
  48. }
  49. @(private)
  50. hex_digit :: proc(char: byte) -> (u8, bool) {
  51. switch char {
  52. case '0' ..= '9': return char - '0', true
  53. case 'a' ..= 'f': return char - 'a' + 10, true
  54. case 'A' ..= 'F': return char - 'A' + 10, true
  55. case: return 0, false
  56. }
  57. }