mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-17 08:21:25 -07:00
Merge branch 'master' into macharena
This commit is contained in:
+33
-3
@@ -144,6 +144,9 @@ buffer_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) {
|
||||
}
|
||||
|
||||
buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int, loc := #caller_location) -> (n: int, err: io.Error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
b.last_read = .Invalid
|
||||
if offset < 0 {
|
||||
err = .Invalid_Offset
|
||||
@@ -246,10 +249,13 @@ buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.
|
||||
}
|
||||
|
||||
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
b.last_read = .Invalid
|
||||
|
||||
if uint(offset) >= len(b.buf) {
|
||||
err = .Invalid_Offset
|
||||
err = .EOF
|
||||
return
|
||||
}
|
||||
n = copy(p, b.buf[offset:])
|
||||
@@ -310,6 +316,27 @@ buffer_unread_rune :: proc(b: ^Buffer) -> io.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
buffer_seek :: proc(b: ^Buffer, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
|
||||
abs: i64
|
||||
switch whence {
|
||||
case .Start:
|
||||
abs = offset
|
||||
case .Current:
|
||||
abs = i64(b.off) + offset
|
||||
case .End:
|
||||
abs = i64(len(b.buf)) + offset
|
||||
case:
|
||||
return 0, .Invalid_Whence
|
||||
}
|
||||
|
||||
abs_int := int(abs)
|
||||
if abs_int < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
b.last_read = .Invalid
|
||||
b.off = abs_int
|
||||
return abs, nil
|
||||
}
|
||||
|
||||
buffer_read_bytes :: proc(b: ^Buffer, delim: byte) -> (line: []byte, err: io.Error) {
|
||||
i := index_byte(b.buf[b.off:], delim)
|
||||
@@ -395,14 +422,17 @@ _buffer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offse
|
||||
return io._i64_err(buffer_write(b, p))
|
||||
case .Write_At:
|
||||
return io._i64_err(buffer_write_at(b, p, int(offset)))
|
||||
case .Seek:
|
||||
n, err = buffer_seek(b, offset, whence)
|
||||
return
|
||||
case .Size:
|
||||
n = i64(buffer_capacity(b))
|
||||
n = i64(buffer_length(b))
|
||||
return
|
||||
case .Destroy:
|
||||
buffer_destroy(b)
|
||||
return
|
||||
case .Query:
|
||||
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Size, .Destroy})
|
||||
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Destroy, .Query})
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ Inputs:
|
||||
Returns:
|
||||
- index: The index of the byte `c`, or -1 if it was not found.
|
||||
*/
|
||||
index_byte :: proc(s: []byte, c: byte) -> (index: int) #no_bounds_check {
|
||||
index_byte :: proc "contextless" (s: []byte, c: byte) -> (index: int) #no_bounds_check {
|
||||
i, l := 0, len(s)
|
||||
|
||||
// Guard against small strings. On modern systems, it is ALWAYS
|
||||
@@ -469,18 +469,16 @@ Inputs:
|
||||
Returns:
|
||||
- index: The index of the byte `c`, or -1 if it was not found.
|
||||
*/
|
||||
last_index_byte :: proc(s: []byte, c: byte) -> int #no_bounds_check {
|
||||
last_index_byte :: proc "contextless" (s: []byte, c: byte) -> int #no_bounds_check {
|
||||
i := len(s)
|
||||
|
||||
// Guard against small strings. On modern systems, it is ALWAYS
|
||||
// worth vectorizing assuming there is a hardware vector unit, and
|
||||
// the data size is large enough.
|
||||
if i < SIMD_REG_SIZE_128 {
|
||||
if i > 0 { // Handle s == nil.
|
||||
for /**/; i >= 0; i -= 1 {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
#reverse for ch, j in s {
|
||||
if ch == c {
|
||||
return j
|
||||
}
|
||||
}
|
||||
return -1
|
||||
|
||||
@@ -9,10 +9,11 @@ Reader :: struct {
|
||||
prev_rune: int, // previous reading index of rune or < 0
|
||||
}
|
||||
|
||||
reader_init :: proc(r: ^Reader, s: []byte) {
|
||||
reader_init :: proc(r: ^Reader, s: []byte) -> io.Stream {
|
||||
r.s = s
|
||||
r.i = 0
|
||||
r.prev_rune = -1
|
||||
return reader_to_stream(r)
|
||||
}
|
||||
|
||||
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
|
||||
@@ -33,6 +34,9 @@ reader_size :: proc(r: ^Reader) -> i64 {
|
||||
}
|
||||
|
||||
reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if r.i >= i64(len(r.s)) {
|
||||
return 0, .EOF
|
||||
}
|
||||
@@ -42,6 +46,9 @@ reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
|
||||
return
|
||||
}
|
||||
reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if off < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
@@ -97,7 +104,6 @@ reader_unread_rune :: proc(r: ^Reader) -> io.Error {
|
||||
return nil
|
||||
}
|
||||
reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
|
||||
r.prev_rune = -1
|
||||
abs: i64
|
||||
switch whence {
|
||||
case .Start:
|
||||
@@ -114,6 +120,7 @@ reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.E
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
r.i = abs
|
||||
r.prev_rune = -1
|
||||
return abs, nil
|
||||
}
|
||||
reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
|
||||
@@ -98,6 +98,14 @@ when ODIN_OS == .Haiku {
|
||||
ERANGE :: B_POSIX_ERROR_BASE + 17
|
||||
}
|
||||
|
||||
when ODIN_OS == .JS {
|
||||
_ :: libc
|
||||
_get_errno :: proc "c" () -> ^int {
|
||||
@(static) errno: int
|
||||
return &errno
|
||||
}
|
||||
}
|
||||
|
||||
// Odin has no way to make an identifier "errno" behave as a function call to
|
||||
// read the value, or to produce an lvalue such that you can assign a different
|
||||
// error value to errno. To work around this, just expose it as a function like
|
||||
|
||||
+25
-1
@@ -89,6 +89,30 @@ when ODIN_OS == .Linux {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .JS {
|
||||
fpos_t :: struct #raw_union { _: [16]char, _: longlong, _: double, }
|
||||
|
||||
_IOFBF :: 0
|
||||
_IOLBF :: 1
|
||||
_IONBF :: 2
|
||||
|
||||
BUFSIZ :: 1024
|
||||
|
||||
EOF :: int(-1)
|
||||
|
||||
FOPEN_MAX :: 1000
|
||||
|
||||
FILENAME_MAX :: 4096
|
||||
|
||||
L_tmpnam :: 20
|
||||
|
||||
SEEK_SET :: 0
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
TMP_MAX :: 308915776
|
||||
}
|
||||
|
||||
when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
|
||||
fpos_t :: distinct i64
|
||||
|
||||
@@ -368,7 +392,7 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
|
||||
return 0, .Empty
|
||||
|
||||
case .Query:
|
||||
return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size })
|
||||
return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ when ODIN_OS == .Windows {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
@(require)
|
||||
import "base:runtime"
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
RAND_MAX :: 0x7fff
|
||||
|
||||
@@ -145,6 +148,10 @@ aligned_alloc :: #force_inline proc "c" (alignment, size: size_t) -> rawptr {
|
||||
_aligned_malloc :: proc(size, alignment: size_t) -> rawptr ---
|
||||
}
|
||||
return _aligned_malloc(size=size, alignment=alignment)
|
||||
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||
context = runtime.default_context()
|
||||
data, _ := runtime.mem_alloc_bytes(auto_cast size, auto_cast alignment)
|
||||
return raw_data(data)
|
||||
} else {
|
||||
foreign libc {
|
||||
aligned_alloc :: proc(alignment, size: size_t) -> rawptr ---
|
||||
@@ -160,6 +167,9 @@ aligned_free :: #force_inline proc "c" (ptr: rawptr) {
|
||||
_aligned_free :: proc(ptr: rawptr) ---
|
||||
}
|
||||
_aligned_free(ptr)
|
||||
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||
context = runtime.default_context()
|
||||
runtime.mem_free(ptr)
|
||||
} else {
|
||||
free(ptr)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ when ODIN_OS == .Windows {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.24.2 Copying functions
|
||||
memcpy :: proc(s1, s2: rawptr, n: size_t) -> rawptr ---
|
||||
|
||||
@@ -45,7 +45,7 @@ when ODIN_OS == .Windows {
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku {
|
||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Haiku || ODIN_OS == .JS {
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
// 7.27.2 Time manipulation functions
|
||||
@@ -79,7 +79,7 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS =
|
||||
} else {
|
||||
@(private) LDIFFTIME :: "difftime"
|
||||
@(private) LMKTIME :: "mktime"
|
||||
@(private) LTIME :: "ltime"
|
||||
@(private) LTIME :: "time"
|
||||
@(private) LCTIME :: "ctime"
|
||||
@(private) LGMTIME :: "gmtime"
|
||||
@(private) LLOCALTIME :: "localtime"
|
||||
|
||||
@@ -14,7 +14,7 @@ when ODIN_OS == .Windows {
|
||||
wctrans_t :: distinct wchar_t
|
||||
wctype_t :: distinct ushort
|
||||
|
||||
} else when ODIN_OS == .Linux {
|
||||
} else when ODIN_OS == .Linux || ODIN_OS == .JS {
|
||||
wctrans_t :: distinct intptr_t
|
||||
wctype_t :: distinct ulong
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
Ginger Bill: Cosmetic changes.
|
||||
|
||||
A small GZIP implementation as an example.
|
||||
*/
|
||||
|
||||
/*
|
||||
Example:
|
||||
import "core:bytes"
|
||||
import "core:os"
|
||||
import "core:compress"
|
||||
import "core:fmt"
|
||||
|
||||
// Small GZIP file with fextra, fname and fcomment present.
|
||||
@private
|
||||
TEST: []u8 = {
|
||||
0x1f, 0x8b, 0x08, 0x1c, 0xcb, 0x3b, 0x3a, 0x5a,
|
||||
0x02, 0x03, 0x07, 0x00, 0x61, 0x62, 0x03, 0x00,
|
||||
0x63, 0x64, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x00, 0x54, 0x68, 0x69, 0x73,
|
||||
0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2b, 0x48,
|
||||
0xac, 0xcc, 0xc9, 0x4f, 0x4c, 0x01, 0x00, 0x15,
|
||||
0x6a, 0x2c, 0x42, 0x07, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
// Set up output buffer.
|
||||
buf := bytes.Buffer{}
|
||||
|
||||
stdout :: proc(s: string) {
|
||||
os.write_string(os.stdout, s)
|
||||
}
|
||||
stderr :: proc(s: string) {
|
||||
os.write_string(os.stderr, s)
|
||||
}
|
||||
|
||||
args := os.args
|
||||
|
||||
if len(args) < 2 {
|
||||
stderr("No input file specified.\n")
|
||||
err := load(data=TEST, buf=&buf, known_gzip_size=len(TEST))
|
||||
if err == nil {
|
||||
stdout("Displaying test vector: ")
|
||||
stdout(bytes.buffer_to_string(&buf))
|
||||
stdout("\n")
|
||||
} else {
|
||||
fmt.printf("gzip.load returned %v\n", err)
|
||||
}
|
||||
bytes.buffer_destroy(&buf)
|
||||
os.exit(0)
|
||||
}
|
||||
|
||||
// The rest are all files.
|
||||
args = args[1:]
|
||||
err: Error
|
||||
|
||||
for file in args {
|
||||
if file == "-" {
|
||||
// Read from stdin
|
||||
s := os.stream_from_handle(os.stdin)
|
||||
ctx := &compress.Context_Stream_Input{
|
||||
input = s,
|
||||
}
|
||||
err = load(ctx, &buf)
|
||||
} else {
|
||||
err = load(file, &buf)
|
||||
}
|
||||
if err != nil {
|
||||
if err != E_General.File_Not_Found {
|
||||
stderr("File not found: ")
|
||||
stderr(file)
|
||||
stderr("\n")
|
||||
os.exit(1)
|
||||
}
|
||||
stderr("GZIP returned an error.\n")
|
||||
bytes.buffer_destroy(&buf)
|
||||
os.exit(2)
|
||||
}
|
||||
stdout(bytes.buffer_to_string(&buf))
|
||||
}
|
||||
bytes.buffer_destroy(&buf)
|
||||
}
|
||||
*/
|
||||
package compress_gzip
|
||||
@@ -1,89 +0,0 @@
|
||||
//+build ignore
|
||||
package compress_gzip
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
Ginger Bill: Cosmetic changes.
|
||||
|
||||
A small GZIP implementation as an example.
|
||||
*/
|
||||
|
||||
import "core:bytes"
|
||||
import "core:os"
|
||||
import "core:compress"
|
||||
import "core:fmt"
|
||||
|
||||
// Small GZIP file with fextra, fname and fcomment present.
|
||||
@private
|
||||
TEST: []u8 = {
|
||||
0x1f, 0x8b, 0x08, 0x1c, 0xcb, 0x3b, 0x3a, 0x5a,
|
||||
0x02, 0x03, 0x07, 0x00, 0x61, 0x62, 0x03, 0x00,
|
||||
0x63, 0x64, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x00, 0x54, 0x68, 0x69, 0x73,
|
||||
0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2b, 0x48,
|
||||
0xac, 0xcc, 0xc9, 0x4f, 0x4c, 0x01, 0x00, 0x15,
|
||||
0x6a, 0x2c, 0x42, 0x07, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
// Set up output buffer.
|
||||
buf := bytes.Buffer{}
|
||||
|
||||
stdout :: proc(s: string) {
|
||||
os.write_string(os.stdout, s)
|
||||
}
|
||||
stderr :: proc(s: string) {
|
||||
os.write_string(os.stderr, s)
|
||||
}
|
||||
|
||||
args := os.args
|
||||
|
||||
if len(args) < 2 {
|
||||
stderr("No input file specified.\n")
|
||||
err := load(data=TEST, buf=&buf, known_gzip_size=len(TEST))
|
||||
if err == nil {
|
||||
stdout("Displaying test vector: ")
|
||||
stdout(bytes.buffer_to_string(&buf))
|
||||
stdout("\n")
|
||||
} else {
|
||||
fmt.printf("gzip.load returned %v\n", err)
|
||||
}
|
||||
bytes.buffer_destroy(&buf)
|
||||
os.exit(0)
|
||||
}
|
||||
|
||||
// The rest are all files.
|
||||
args = args[1:]
|
||||
err: Error
|
||||
|
||||
for file in args {
|
||||
if file == "-" {
|
||||
// Read from stdin
|
||||
s := os.stream_from_handle(os.stdin)
|
||||
ctx := &compress.Context_Stream_Input{
|
||||
input = s,
|
||||
}
|
||||
err = load(ctx, &buf)
|
||||
} else {
|
||||
err = load(file, &buf)
|
||||
}
|
||||
if err != nil {
|
||||
if err != E_General.File_Not_Found {
|
||||
stderr("File not found: ")
|
||||
stderr(file)
|
||||
stderr("\n")
|
||||
os.exit(1)
|
||||
}
|
||||
stderr("GZIP returned an error.\n")
|
||||
bytes.buffer_destroy(&buf)
|
||||
os.exit(2)
|
||||
}
|
||||
stdout(bytes.buffer_to_string(&buf))
|
||||
}
|
||||
bytes.buffer_destroy(&buf)
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
which is an English word model.
|
||||
*/
|
||||
|
||||
// package shoco is an implementation of the shoco short string compressor
|
||||
package compress_shoco
|
||||
|
||||
DEFAULT_MODEL :: Shoco_Model {
|
||||
@@ -145,4 +144,4 @@ DEFAULT_MODEL :: Shoco_Model {
|
||||
{ 0xc0000000, 2, 4, { 25, 22, 19, 16, 16, 16, 16, 16 }, { 15, 7, 7, 7, 0, 0, 0, 0 }, 0xe0, 0xc0 },
|
||||
{ 0xe0000000, 4, 8, { 23, 19, 15, 11, 8, 5, 2, 0 }, { 31, 15, 15, 15, 7, 7, 7, 3 }, 0xf0, 0xe0 },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
An implementation of [shoco](https://github.com/Ed-von-Schleck/shoco) by Christian Schramm.
|
||||
*/
|
||||
|
||||
// package shoco is an implementation of the shoco short string compressor
|
||||
// package shoco is an implementation of the shoco short string compressor.
|
||||
package compress_shoco
|
||||
|
||||
import "base:intrinsics"
|
||||
@@ -308,4 +308,4 @@ compress_string :: proc(input: string, model := DEFAULT_MODEL, allocator := cont
|
||||
resize(&buf, length) or_return
|
||||
return buf[:length], result
|
||||
}
|
||||
compress :: proc{compress_string_to_buffer, compress_string}
|
||||
compress :: proc{compress_string_to_buffer, compress_string}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
|
||||
An example of how to use `zlib.inflate`.
|
||||
*/
|
||||
|
||||
/*
|
||||
Example:
|
||||
package main
|
||||
|
||||
import "core:bytes"
|
||||
import "core:fmt"
|
||||
|
||||
main :: proc() {
|
||||
ODIN_DEMO := []u8{
|
||||
120, 218, 101, 144, 65, 110, 131, 48, 16, 69, 215, 246, 41, 190, 44, 69, 73, 32, 148, 182,
|
||||
75, 75, 28, 32, 251, 46, 217, 88, 238, 0, 86, 192, 32, 219, 36, 170, 170, 172, 122, 137,
|
||||
238, 122, 197, 30, 161, 70, 162, 20, 81, 203, 139, 25, 191, 255, 191, 60, 51, 40, 125, 81,
|
||||
53, 33, 144, 15, 156, 155, 110, 232, 93, 128, 208, 189, 35, 89, 117, 65, 112, 222, 41, 99,
|
||||
33, 37, 6, 215, 235, 195, 17, 239, 156, 197, 170, 118, 170, 131, 44, 32, 82, 164, 72, 240,
|
||||
253, 245, 249, 129, 12, 185, 224, 76, 105, 61, 118, 99, 171, 66, 239, 38, 193, 35, 103, 85,
|
||||
172, 66, 127, 33, 139, 24, 244, 235, 141, 49, 204, 223, 76, 208, 205, 204, 166, 7, 173, 60,
|
||||
97, 159, 238, 37, 214, 41, 105, 129, 167, 5, 102, 27, 152, 173, 97, 178, 129, 73, 129, 231,
|
||||
5, 230, 27, 152, 175, 225, 52, 192, 127, 243, 170, 157, 149, 18, 121, 142, 115, 109, 227, 122,
|
||||
64, 87, 114, 111, 161, 49, 182, 6, 181, 158, 162, 226, 206, 167, 27, 215, 246, 48, 56, 99,
|
||||
67, 117, 16, 47, 13, 45, 35, 151, 98, 231, 75, 1, 173, 90, 61, 101, 146, 71, 136, 244,
|
||||
170, 218, 145, 176, 123, 45, 173, 56, 113, 134, 191, 51, 219, 78, 235, 95, 28, 249, 253, 7,
|
||||
159, 150, 133, 125,
|
||||
}
|
||||
OUTPUT_SIZE :: 432
|
||||
|
||||
buf: bytes.Buffer
|
||||
|
||||
// We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
|
||||
err := inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE)
|
||||
defer bytes.buffer_destroy(&buf)
|
||||
|
||||
if err != nil {
|
||||
fmt.printf("\nError: %v\n", err)
|
||||
}
|
||||
s := bytes.buffer_to_string(&buf)
|
||||
fmt.printf("Input: %v bytes, output (%v bytes):\n%v\n", len(ODIN_DEMO), len(s), s)
|
||||
assert(len(s) == OUTPUT_SIZE)
|
||||
}
|
||||
*/
|
||||
package compress_zlib
|
||||
@@ -1,47 +0,0 @@
|
||||
//+build ignore
|
||||
package compress_zlib
|
||||
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
|
||||
An example of how to use `zlib.inflate`.
|
||||
*/
|
||||
|
||||
import "core:bytes"
|
||||
import "core:fmt"
|
||||
|
||||
main :: proc() {
|
||||
ODIN_DEMO := []u8{
|
||||
120, 218, 101, 144, 65, 110, 131, 48, 16, 69, 215, 246, 41, 190, 44, 69, 73, 32, 148, 182,
|
||||
75, 75, 28, 32, 251, 46, 217, 88, 238, 0, 86, 192, 32, 219, 36, 170, 170, 172, 122, 137,
|
||||
238, 122, 197, 30, 161, 70, 162, 20, 81, 203, 139, 25, 191, 255, 191, 60, 51, 40, 125, 81,
|
||||
53, 33, 144, 15, 156, 155, 110, 232, 93, 128, 208, 189, 35, 89, 117, 65, 112, 222, 41, 99,
|
||||
33, 37, 6, 215, 235, 195, 17, 239, 156, 197, 170, 118, 170, 131, 44, 32, 82, 164, 72, 240,
|
||||
253, 245, 249, 129, 12, 185, 224, 76, 105, 61, 118, 99, 171, 66, 239, 38, 193, 35, 103, 85,
|
||||
172, 66, 127, 33, 139, 24, 244, 235, 141, 49, 204, 223, 76, 208, 205, 204, 166, 7, 173, 60,
|
||||
97, 159, 238, 37, 214, 41, 105, 129, 167, 5, 102, 27, 152, 173, 97, 178, 129, 73, 129, 231,
|
||||
5, 230, 27, 152, 175, 225, 52, 192, 127, 243, 170, 157, 149, 18, 121, 142, 115, 109, 227, 122,
|
||||
64, 87, 114, 111, 161, 49, 182, 6, 181, 158, 162, 226, 206, 167, 27, 215, 246, 48, 56, 99,
|
||||
67, 117, 16, 47, 13, 45, 35, 151, 98, 231, 75, 1, 173, 90, 61, 101, 146, 71, 136, 244,
|
||||
170, 218, 145, 176, 123, 45, 173, 56, 113, 134, 191, 51, 219, 78, 235, 95, 28, 249, 253, 7,
|
||||
159, 150, 133, 125,
|
||||
}
|
||||
OUTPUT_SIZE :: 432
|
||||
|
||||
buf: bytes.Buffer
|
||||
|
||||
// We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
|
||||
err := inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE)
|
||||
defer bytes.buffer_destroy(&buf)
|
||||
|
||||
if err != nil {
|
||||
fmt.printf("\nError: %v\n", err)
|
||||
}
|
||||
s := bytes.buffer_to_string(&buf)
|
||||
fmt.printf("Input: %v bytes, output (%v bytes):\n%v\n", len(ODIN_DEMO), len(s), s)
|
||||
assert(len(s) == OUTPUT_SIZE)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//+vet !using-param
|
||||
#+vet !using-param
|
||||
package compress_zlib
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package container_dynamic_bit_array
|
||||
|
||||
import "base:builtin"
|
||||
import "base:intrinsics"
|
||||
import "core:mem"
|
||||
|
||||
@@ -18,7 +19,7 @@ NUM_BITS :: 64
|
||||
Bit_Array :: struct {
|
||||
bits: [dynamic]u64,
|
||||
bias: int,
|
||||
max_index: int,
|
||||
length: int,
|
||||
free_pointer: bool,
|
||||
}
|
||||
|
||||
@@ -52,9 +53,9 @@ Returns:
|
||||
*/
|
||||
iterate_by_all :: proc (it: ^Bit_Array_Iterator) -> (set: bool, index: int, ok: bool) {
|
||||
index = it.word_idx * NUM_BITS + int(it.bit_idx) + it.array.bias
|
||||
if index > it.array.max_index { return false, 0, false }
|
||||
if index >= it.array.length + it.array.bias { return false, 0, false }
|
||||
|
||||
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||
word := it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
|
||||
set = (word >> it.bit_idx & 1) == 1
|
||||
|
||||
it.bit_idx += 1
|
||||
@@ -106,22 +107,22 @@ Returns:
|
||||
*/
|
||||
@(private="file")
|
||||
iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) -> (index: int, ok: bool) {
|
||||
word := it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||
word := it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
|
||||
when ! ITERATE_SET_BITS { word = ~word }
|
||||
|
||||
// If the word is empty or we have already gone over all the bits in it,
|
||||
// b.bit_idx is greater than the index of any set bit in the word,
|
||||
// meaning that word >> b.bit_idx == 0.
|
||||
for it.word_idx < len(it.array.bits) && word >> it.bit_idx == 0 {
|
||||
for it.word_idx < builtin.len(it.array.bits) && word >> it.bit_idx == 0 {
|
||||
it.word_idx += 1
|
||||
it.bit_idx = 0
|
||||
word = it.array.bits[it.word_idx] if len(it.array.bits) > it.word_idx else 0
|
||||
word = it.array.bits[it.word_idx] if builtin.len(it.array.bits) > it.word_idx else 0
|
||||
when ! ITERATE_SET_BITS { word = ~word }
|
||||
}
|
||||
|
||||
// If we are iterating the set bits, reaching the end of the array means we have no more bits to check
|
||||
when ITERATE_SET_BITS {
|
||||
if it.word_idx >= len(it.array.bits) {
|
||||
if it.word_idx >= builtin.len(it.array.bits) {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
@@ -135,7 +136,7 @@ iterate_internal_ :: proc (it: ^Bit_Array_Iterator, $ITERATE_SET_BITS: bool) ->
|
||||
it.bit_idx = 0
|
||||
it.word_idx += 1
|
||||
}
|
||||
return index, index <= it.array.max_index
|
||||
return index, index < it.array.length + it.array.bias
|
||||
}
|
||||
/*
|
||||
Gets the state of a bit in the bit-array
|
||||
@@ -160,7 +161,7 @@ get :: proc(ba: ^Bit_Array, #any_int index: uint) -> (res: bool, ok: bool) #opti
|
||||
If we `get` a bit that doesn't fit in the Bit Array, it's naturally `false`.
|
||||
This early-out prevents unnecessary resizing.
|
||||
*/
|
||||
if leg_index + 1 > len(ba.bits) { return false, true }
|
||||
if leg_index + 1 > builtin.len(ba.bits) { return false, true }
|
||||
|
||||
val := u64(1 << uint(bit_index))
|
||||
res = ba.bits[leg_index] & val == val
|
||||
@@ -208,7 +209,7 @@ set :: proc(ba: ^Bit_Array, #any_int index: uint, set_to: bool = true, allocator
|
||||
|
||||
resize_if_needed(ba, leg_index) or_return
|
||||
|
||||
ba.max_index = max(idx, ba.max_index)
|
||||
ba.length = max(1 + idx, ba.length)
|
||||
|
||||
if set_to {
|
||||
ba.bits[leg_index] |= 1 << uint(bit_index)
|
||||
@@ -261,6 +262,9 @@ unsafe_unset :: proc(b: ^Bit_Array, bit: int) #no_bounds_check {
|
||||
/*
|
||||
A helper function to create a Bit Array with optional bias, in case your smallest index is non-zero (including negative).
|
||||
|
||||
The range of bits created by this procedure is `min_index..<max_index`, and the
|
||||
array will be able to expand beyond `max_index` if needed.
|
||||
|
||||
*Allocates (`new(Bit_Array) & make(ba.bits)`)*
|
||||
|
||||
Inputs:
|
||||
@@ -275,7 +279,7 @@ create :: proc(max_index: int, min_index: int = 0, allocator := context.allocato
|
||||
context.allocator = allocator
|
||||
size_in_bits := max_index - min_index
|
||||
|
||||
if size_in_bits < 1 { return {}, false }
|
||||
if size_in_bits < 0 { return {}, false }
|
||||
|
||||
legs := size_in_bits >> INDEX_SHIFT
|
||||
if size_in_bits & INDEX_MASK > 0 {legs+=1}
|
||||
@@ -284,7 +288,7 @@ create :: proc(max_index: int, min_index: int = 0, allocator := context.allocato
|
||||
res = new(Bit_Array)
|
||||
res.bits = bits
|
||||
res.bias = min_index
|
||||
res.max_index = max_index
|
||||
res.length = max_index - min_index
|
||||
res.free_pointer = true
|
||||
return
|
||||
}
|
||||
@@ -299,6 +303,48 @@ clear :: proc(ba: ^Bit_Array) {
|
||||
mem.zero_slice(ba.bits[:])
|
||||
}
|
||||
/*
|
||||
Gets the length of set and unset valid bits in the Bit_Array.
|
||||
|
||||
Inputs:
|
||||
- ba: The target Bit_Array
|
||||
|
||||
Returns:
|
||||
- length: The length of valid bits.
|
||||
*/
|
||||
len :: proc(ba: ^Bit_Array) -> (length: int) {
|
||||
if ba == nil { return }
|
||||
return ba.length
|
||||
}
|
||||
/*
|
||||
Shrinks the Bit_Array's backing storage to the smallest possible size.
|
||||
|
||||
Inputs:
|
||||
- ba: The target Bit_Array
|
||||
*/
|
||||
shrink :: proc(ba: ^Bit_Array) #no_bounds_check {
|
||||
if ba == nil { return }
|
||||
legs_needed := builtin.len(ba.bits)
|
||||
for i := legs_needed - 1; i >= 0; i -= 1 {
|
||||
if ba.bits[i] == 0 {
|
||||
legs_needed -= 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if legs_needed == builtin.len(ba.bits) {
|
||||
return
|
||||
}
|
||||
ba.length = 0
|
||||
if legs_needed > 0 {
|
||||
if legs_needed > 1 {
|
||||
ba.length = (legs_needed - 1) * NUM_BITS
|
||||
}
|
||||
ba.length += NUM_BITS - int(intrinsics.count_leading_zeros(ba.bits[legs_needed - 1]))
|
||||
}
|
||||
resize(&ba.bits, legs_needed)
|
||||
builtin.shrink(&ba.bits)
|
||||
}
|
||||
/*
|
||||
Deallocates the Bit_Array and its backing storage
|
||||
|
||||
Inputs:
|
||||
@@ -321,8 +367,8 @@ resize_if_needed :: proc(ba: ^Bit_Array, legs: int, allocator := context.allocat
|
||||
|
||||
context.allocator = allocator
|
||||
|
||||
if legs + 1 > len(ba.bits) {
|
||||
if legs + 1 > builtin.len(ba.bits) {
|
||||
resize(&ba.bits, legs + 1)
|
||||
}
|
||||
return len(ba.bits) > legs
|
||||
return builtin.len(ba.bits) > legs
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
The Bit Array can be used in several ways:
|
||||
|
||||
- By default you don't need to instantiate a Bit Array:
|
||||
|
||||
By default you don't need to instantiate a Bit Array.
|
||||
Example:
|
||||
package test
|
||||
|
||||
import "core:fmt"
|
||||
@@ -22,8 +22,8 @@ The Bit Array can be used in several ways:
|
||||
destroy(&bits)
|
||||
}
|
||||
|
||||
- A Bit Array can optionally allow for negative indices, if the minimum value was given during creation:
|
||||
|
||||
A Bit Array can optionally allow for negative indices, if the minimum value was given during creation.
|
||||
Example:
|
||||
package test
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
/*
|
||||
Package list implements an intrusive doubly-linked list.
|
||||
|
||||
An intrusive container requires a `Node` to be embedded in your own structure, like this:
|
||||
|
||||
An intrusive container requires a `Node` to be embedded in your own structure, like this.
|
||||
Example:
|
||||
My_String :: struct {
|
||||
node: list.Node,
|
||||
value: string,
|
||||
}
|
||||
|
||||
Embedding the members of a `list.Node` in your structure with the `using` keyword is also allowed:
|
||||
|
||||
Embedding the members of a `list.Node` in your structure with the `using` keyword is also allowed.
|
||||
Example:
|
||||
My_String :: struct {
|
||||
using node: list.Node,
|
||||
value: string,
|
||||
}
|
||||
|
||||
Here is a full example:
|
||||
|
||||
Here is a full example.
|
||||
Example:
|
||||
package test
|
||||
|
||||
import "core:fmt"
|
||||
@@ -42,5 +42,8 @@ Here is a full example:
|
||||
value: string,
|
||||
}
|
||||
|
||||
Output:
|
||||
Hello
|
||||
World
|
||||
*/
|
||||
package container_intrusive_list
|
||||
|
||||
@@ -139,9 +139,13 @@ clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) {
|
||||
resize(a, 0)
|
||||
}
|
||||
|
||||
push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) {
|
||||
n := copy(a.data[a.len:], items[:])
|
||||
a.len += n
|
||||
push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) -> bool {
|
||||
if a.len + builtin.len(items) <= cap(a^) {
|
||||
n := copy(a.data[a.len:], items[:])
|
||||
a.len += n
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
inject_at :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T, index: int) -> bool #no_bounds_check {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build amd64
|
||||
#+build amd64
|
||||
package aes_hw_intel
|
||||
|
||||
import "core:sys/info"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//+build amd64
|
||||
#+build amd64
|
||||
package aes_hw_intel
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//+build amd64
|
||||
#+build amd64
|
||||
package aes_hw_intel
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build amd64
|
||||
#+build amd64
|
||||
package chacha20_simd256
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build !amd64
|
||||
#+build !amd64
|
||||
package chacha20_simd256
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
+35
-36
@@ -10,49 +10,48 @@ algorithm.
|
||||
WARNING: Reusing the same key + iv to seal (encrypt) multiple messages
|
||||
results in catastrophic loss of security for most algorithms.
|
||||
|
||||
```odin
|
||||
package aead_example
|
||||
Example:
|
||||
package aead_example
|
||||
|
||||
import "core:bytes"
|
||||
import "core:crypto"
|
||||
import "core:crypto/aead"
|
||||
import "core:bytes"
|
||||
import "core:crypto"
|
||||
import "core:crypto/aead"
|
||||
|
||||
main :: proc() {
|
||||
algo := aead.Algorithm.XCHACHA20POLY1305
|
||||
main :: proc() {
|
||||
algo := aead.Algorithm.XCHACHA20POLY1305
|
||||
|
||||
// The example added associated data, and plaintext.
|
||||
aad_str := "Get your ass in gear boys."
|
||||
pt_str := "They're immanetizing the Eschaton."
|
||||
// The example added associated data, and plaintext.
|
||||
aad_str := "Get your ass in gear boys."
|
||||
pt_str := "They're immanetizing the Eschaton."
|
||||
|
||||
aad := transmute([]byte)aad_str
|
||||
plaintext := transmute([]byte)pt_str
|
||||
pt_len := len(plaintext)
|
||||
aad := transmute([]byte)aad_str
|
||||
plaintext := transmute([]byte)pt_str
|
||||
pt_len := len(plaintext)
|
||||
|
||||
// Generate a random key for the purposes of illustration.
|
||||
key := make([]byte, aead.KEY_SIZES[algo])
|
||||
defer delete(key)
|
||||
crypto.rand_bytes(key)
|
||||
// Generate a random key for the purposes of illustration.
|
||||
key := make([]byte, aead.KEY_SIZES[algo])
|
||||
defer delete(key)
|
||||
crypto.rand_bytes(key)
|
||||
|
||||
// `ciphertext || tag`, is a common way data is transmitted, so
|
||||
// demonstrate that.
|
||||
buf := make([]byte, pt_len + aead.TAG_SIZES[algo])
|
||||
defer delete(buf)
|
||||
ciphertext, tag := buf[:pt_len], buf[pt_len:]
|
||||
// `ciphertext || tag`, is a common way data is transmitted, so
|
||||
// demonstrate that.
|
||||
buf := make([]byte, pt_len + aead.TAG_SIZES[algo])
|
||||
defer delete(buf)
|
||||
ciphertext, tag := buf[:pt_len], buf[pt_len:]
|
||||
|
||||
// Seal the AAD + Plaintext.
|
||||
iv := make([]byte, aead.IV_SIZES[algo])
|
||||
defer delete(iv)
|
||||
crypto.rand_bytes(iv) // Random IVs are safe with XChaCha20-Poly1305.
|
||||
aead.seal(algo, ciphertext, tag, key, iv, aad, plaintext)
|
||||
// Seal the AAD + Plaintext.
|
||||
iv := make([]byte, aead.IV_SIZES[algo])
|
||||
defer delete(iv)
|
||||
crypto.rand_bytes(iv) // Random IVs are safe with XChaCha20-Poly1305.
|
||||
aead.seal(algo, ciphertext, tag, key, iv, aad, plaintext)
|
||||
|
||||
// Open the AAD + Ciphertext.
|
||||
opened_pt := buf[:pt_len]
|
||||
if ok := aead.open(algo, opened_pt, key, iv, aad, ciphertext, tag); !ok {
|
||||
panic("aead example: failed to open")
|
||||
// Open the AAD + Ciphertext.
|
||||
opened_pt := buf[:pt_len]
|
||||
if ok := aead.open(algo, opened_pt, key, iv, aad, ciphertext, tag); !ok {
|
||||
panic("aead example: failed to open")
|
||||
}
|
||||
|
||||
assert(bytes.equal(opened_pt, plaintext))
|
||||
}
|
||||
|
||||
assert(bytes.equal(opened_pt, plaintext))
|
||||
}
|
||||
```
|
||||
*/
|
||||
package aead
|
||||
package aead
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
package aes implements the AES block cipher and some common modes.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf
|
||||
- https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
|
||||
- https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197-upd1.pdf ]]
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf ]]
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf ]]
|
||||
*/
|
||||
package aes
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build amd64
|
||||
#+build amd64
|
||||
package aes
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build amd64
|
||||
#+build amd64
|
||||
package aes
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build amd64
|
||||
#+build amd64
|
||||
package aes
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build !amd64
|
||||
#+build !amd64
|
||||
package aes
|
||||
|
||||
@(private = "file")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build amd64
|
||||
#+build amd64
|
||||
package aes
|
||||
|
||||
import "core:crypto/_aes/hw_intel"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
package blake2b implements the BLAKE2b hash algorithm.
|
||||
|
||||
See:
|
||||
- https://datatracker.ietf.org/doc/html/rfc7693
|
||||
- https://www.blake2.net
|
||||
- [[ https://datatracker.ietf.org/doc/html/rfc7693 ]]
|
||||
- [[ https://www.blake2.net ]]
|
||||
*/
|
||||
package blake2b
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
package blake2s implements the BLAKE2s hash algorithm.
|
||||
|
||||
See:
|
||||
- https://datatracker.ietf.org/doc/html/rfc7693
|
||||
- https://www.blake2.net/
|
||||
- [[ https://datatracker.ietf.org/doc/html/rfc7693 ]]
|
||||
- [[ https://www.blake2.net/ ]]
|
||||
*/
|
||||
package blake2s
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
package chacha20 implements the ChaCha20 and XChaCha20 stream ciphers.
|
||||
|
||||
See:
|
||||
- https://datatracker.ietf.org/doc/html/rfc8439
|
||||
- https://datatracker.ietf.org/doc/draft-irtf-cfrg-xchacha/03/
|
||||
- [[ https://datatracker.ietf.org/doc/html/rfc8439 ]]
|
||||
- [[ https://datatracker.ietf.org/doc/draft-irtf-cfrg-xchacha/03/ ]]
|
||||
*/
|
||||
package chacha20
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ AEAD_XChaCha20_Poly1305 Authenticated Encryption with Additional Data
|
||||
algorithms.
|
||||
|
||||
See:
|
||||
- https://www.rfc-editor.org/rfc/rfc8439
|
||||
- https://datatracker.ietf.org/doc/html/draft-arciszewski-xchacha-03
|
||||
- [[ https://www.rfc-editor.org/rfc/rfc8439 ]]
|
||||
- [[ https://datatracker.ietf.org/doc/html/draft-arciszewski-xchacha-03 ]]
|
||||
*/
|
||||
package chacha20poly1305
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
package ed25519 implements the Ed25519 EdDSA signature algorithm.
|
||||
|
||||
See:
|
||||
- https://datatracker.ietf.org/doc/html/rfc8032
|
||||
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
|
||||
- https://eprint.iacr.org/2020/1244.pdf
|
||||
- [[ https://datatracker.ietf.org/doc/html/rfc8032 ]]
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf ]]
|
||||
- [[ https://eprint.iacr.org/2020/1244.pdf ]]
|
||||
*/
|
||||
package ed25519
|
||||
|
||||
|
||||
+28
-30
@@ -17,46 +17,44 @@ accomplish common tasks.
|
||||
A third optional boolean parameter controls if the file is streamed
|
||||
(default), or or read at once.
|
||||
|
||||
```odin
|
||||
package hash_example
|
||||
Example:
|
||||
package hash_example
|
||||
|
||||
import "core:crypto/hash"
|
||||
import "core:crypto/hash"
|
||||
|
||||
main :: proc() {
|
||||
input := "Feed the fire."
|
||||
main :: proc() {
|
||||
input := "Feed the fire."
|
||||
|
||||
// Compute the digest, using the high level API.
|
||||
returned_digest := hash.hash(hash.Algorithm.SHA512_256, input)
|
||||
defer delete(returned_digest)
|
||||
// Compute the digest, using the high level API.
|
||||
returned_digest := hash.hash(hash.Algorithm.SHA512_256, input)
|
||||
defer delete(returned_digest)
|
||||
|
||||
// Variant that takes a destination buffer, instead of returning
|
||||
// the digest.
|
||||
digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.BLAKE2B]) // @note: Destination buffer has to be at least as big as the digest size of the hash.
|
||||
defer delete(digest)
|
||||
hash.hash(hash.Algorithm.BLAKE2B, input, digest)
|
||||
}
|
||||
```
|
||||
// Variant that takes a destination buffer, instead of returning
|
||||
// the digest.
|
||||
digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.BLAKE2B]) // @note: Destination buffer has to be at least as big as the digest size of the hash.
|
||||
defer delete(digest)
|
||||
hash.hash(hash.Algorithm.BLAKE2B, input, digest)
|
||||
}
|
||||
|
||||
A generic low level API is provided supporting the init/update/final interface
|
||||
that is typical with cryptographic hash function implementations.
|
||||
|
||||
```odin
|
||||
package hash_example
|
||||
Example:
|
||||
package hash_example
|
||||
|
||||
import "core:crypto/hash"
|
||||
import "core:crypto/hash"
|
||||
|
||||
main :: proc() {
|
||||
input := "Let the cinders burn."
|
||||
main :: proc() {
|
||||
input := "Let the cinders burn."
|
||||
|
||||
// Compute the digest, using the low level API.
|
||||
ctx: hash.Context
|
||||
digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.SHA3_512])
|
||||
defer delete(digest)
|
||||
// Compute the digest, using the low level API.
|
||||
ctx: hash.Context
|
||||
digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.SHA3_512])
|
||||
defer delete(digest)
|
||||
|
||||
hash.init(&ctx, hash.Algorithm.SHA3_512)
|
||||
hash.update(&ctx, transmute([]byte)input)
|
||||
hash.final(&ctx, digest)
|
||||
}
|
||||
```
|
||||
hash.init(&ctx, hash.Algorithm.SHA3_512)
|
||||
hash.update(&ctx, transmute([]byte)input)
|
||||
hash.final(&ctx, digest)
|
||||
}
|
||||
*/
|
||||
package crypto_hash
|
||||
package crypto_hash
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package crypto_hash
|
||||
|
||||
/*
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
Copyright 2021 zhibog
|
||||
Made available under the BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
List of contributors:
|
||||
zhibog, dotbmp: Initial implementation.
|
||||
*/
|
||||
|
||||
import "core:io"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
|
||||
// hash_bytes will hash the given input and return the computed digest
|
||||
// in a newly allocated slice.
|
||||
@@ -87,36 +86,3 @@ hash_stream :: proc(
|
||||
|
||||
return dst, io.Error.None
|
||||
}
|
||||
|
||||
// hash_file will read the file provided by the given handle and return the
|
||||
// computed digest in a newly allocated slice.
|
||||
hash_file :: proc(
|
||||
algorithm: Algorithm,
|
||||
hd: os.Handle,
|
||||
load_at_once := false,
|
||||
allocator := context.allocator,
|
||||
) -> (
|
||||
[]byte,
|
||||
io.Error,
|
||||
) {
|
||||
if !load_at_once {
|
||||
return hash_stream(algorithm, os.stream_from_handle(hd), allocator)
|
||||
}
|
||||
|
||||
buf, ok := os.read_entire_file(hd, allocator)
|
||||
if !ok {
|
||||
return nil, io.Error.Unknown
|
||||
}
|
||||
defer delete(buf, allocator)
|
||||
|
||||
return hash_bytes(algorithm, buf, allocator), io.Error.None
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#+build freestanding
|
||||
package crypto_hash
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#+build !freestanding
|
||||
package crypto_hash
|
||||
|
||||
import "core:io"
|
||||
import "core:os"
|
||||
|
||||
// hash_file will read the file provided by the given handle and return the
|
||||
// computed digest in a newly allocated slice.
|
||||
hash_file :: proc(
|
||||
algorithm: Algorithm,
|
||||
hd: os.Handle,
|
||||
load_at_once := false,
|
||||
allocator := context.allocator,
|
||||
) -> (
|
||||
[]byte,
|
||||
io.Error,
|
||||
) {
|
||||
if !load_at_once {
|
||||
return hash_stream(algorithm, os.stream_from_handle(hd), allocator)
|
||||
}
|
||||
|
||||
buf, ok := os.read_entire_file(hd, allocator)
|
||||
if !ok {
|
||||
return nil, io.Error.Unknown
|
||||
}
|
||||
defer delete(buf, allocator)
|
||||
|
||||
return hash_bytes(algorithm, buf, allocator), io.Error.None
|
||||
}
|
||||
|
||||
hash :: proc {
|
||||
hash_stream,
|
||||
hash_file,
|
||||
hash_bytes,
|
||||
hash_string,
|
||||
hash_bytes_to_buffer,
|
||||
hash_string_to_buffer,
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
package hkdf implements the HKDF HMAC-based Extract-and-Expand Key
|
||||
Derivation Function.
|
||||
|
||||
See: https://www.rfc-editor.org/rfc/rfc5869
|
||||
See: [[ https://www.rfc-editor.org/rfc/rfc5869 ]]
|
||||
*/
|
||||
package hkdf
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package hmac implements the HMAC MAC algorithm.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf ]]
|
||||
*/
|
||||
package hmac
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package kmac implements the KMAC MAC algorithm.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf ]]
|
||||
*/
|
||||
package kmac
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ WARNING: The MD5 algorithm is known to be insecure and should only be
|
||||
used for interoperating with legacy applications.
|
||||
|
||||
See:
|
||||
- https://eprint.iacr.org/2005/075
|
||||
- https://datatracker.ietf.org/doc/html/rfc1321
|
||||
- [[ https://eprint.iacr.org/2005/075 ]]
|
||||
- [[ https://datatracker.ietf.org/doc/html/rfc1321 ]]
|
||||
*/
|
||||
package md5
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ WARNING: The SHA1 algorithm is known to be insecure and should only be
|
||||
used for interoperating with legacy applications.
|
||||
|
||||
See:
|
||||
- https://eprint.iacr.org/2017/190
|
||||
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
|
||||
- https://datatracker.ietf.org/doc/html/rfc3174
|
||||
- [[ https://eprint.iacr.org/2017/190 ]]
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf ]]
|
||||
- [[ https://datatracker.ietf.org/doc/html/rfc3174 ]]
|
||||
*/
|
||||
package sha1
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
package pbkdf2 implements the PBKDF2 password-based key derivation function.
|
||||
|
||||
See: https://www.rfc-editor.org/rfc/rfc2898
|
||||
See: [[ https://www.rfc-editor.org/rfc/rfc2898 ]]
|
||||
*/
|
||||
package pbkdf2
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package poly1305 implements the Poly1305 one-time MAC algorithm.
|
||||
|
||||
See:
|
||||
- https://datatracker.ietf.org/doc/html/rfc8439
|
||||
- [[ https://datatracker.ietf.org/doc/html/rfc8439 ]]
|
||||
*/
|
||||
package poly1305
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build freebsd, openbsd, netbsd
|
||||
#+build freebsd, openbsd, netbsd
|
||||
package crypto
|
||||
|
||||
foreign import libc "system:c"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
//+build !linux
|
||||
//+build !windows
|
||||
//+build !openbsd
|
||||
//+build !freebsd
|
||||
//+build !netbsd
|
||||
//+build !darwin
|
||||
//+build !js
|
||||
#+build !linux
|
||||
#+build !windows
|
||||
#+build !openbsd
|
||||
#+build !freebsd
|
||||
#+build !netbsd
|
||||
#+build !darwin
|
||||
#+build !js
|
||||
package crypto
|
||||
|
||||
HAS_RAND_BYTES :: false
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package ristretto255 implement the ristretto255 prime-order group.
|
||||
|
||||
See:
|
||||
- https://www.rfc-editor.org/rfc/rfc9496
|
||||
- [[ https://www.rfc-editor.org/rfc/rfc9496 ]]
|
||||
*/
|
||||
package ristretto255
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
package sha2 implements the SHA2 hash algorithm family.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
|
||||
- https://datatracker.ietf.org/doc/html/rfc3874
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf ]]
|
||||
- [[ https://datatracker.ietf.org/doc/html/rfc3874 ]]
|
||||
*/
|
||||
package sha2
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ pre-standardization Keccak algorithm is required, it can be found in
|
||||
crypto/legacy/keccak.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf ]]
|
||||
*/
|
||||
package sha3
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ package shake implements the SHAKE and cSHAKE XOF algorithm families.
|
||||
The SHA3 hash algorithm can be found in the crypto/sha3.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
|
||||
- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf ]]
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf ]]
|
||||
*/
|
||||
package shake
|
||||
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/*
|
||||
package siphash Implements the SipHash hashing algorithm.
|
||||
|
||||
Use the specific procedures for a certain setup. The generic procedures will default to Siphash 2-4.
|
||||
|
||||
See:
|
||||
- [[ https://github.com/veorq/SipHash ]]
|
||||
- [[ https://www.aumasson.jp/siphash/siphash.pdf ]]
|
||||
*/
|
||||
package siphash
|
||||
|
||||
/*
|
||||
@@ -6,10 +15,6 @@ package siphash
|
||||
|
||||
List of contributors:
|
||||
zhibog: Initial implementation.
|
||||
|
||||
Implementation of the SipHash hashing algorithm, as defined at <https://github.com/veorq/SipHash> and <https://www.aumasson.jp/siphash/siphash.pdf>
|
||||
|
||||
Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4
|
||||
*/
|
||||
|
||||
import "core:crypto"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package sm3 implements the SM3 hash algorithm.
|
||||
|
||||
See:
|
||||
- https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02
|
||||
- [[ https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02 ]]
|
||||
*/
|
||||
package sm3
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package tuplehash implements the TupleHash and TupleHashXOF algorithms.
|
||||
|
||||
See:
|
||||
- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
|
||||
- [[ https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf ]]
|
||||
*/
|
||||
package tuplehash
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package x25519 implements the X25519 (aka curve25519) Elliptic-Curve
|
||||
Diffie-Hellman key exchange protocol.
|
||||
|
||||
See:
|
||||
- https://www.rfc-editor.org/rfc/rfc7748
|
||||
- [[ https://www.rfc-editor.org/rfc/rfc7748 ]]
|
||||
*/
|
||||
package x25519
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//+private file
|
||||
//+build linux, darwin
|
||||
#+private file
|
||||
#+build linux, darwin
|
||||
package debug_trace
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
//+build !windows !linux !darwin
|
||||
#+build !windows
|
||||
#+build !linux
|
||||
#+build !darwin
|
||||
package debug_trace
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//+private
|
||||
//+build windows
|
||||
#+private
|
||||
#+build windows
|
||||
package debug_trace
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -4,7 +4,6 @@ Package `core:dynlib` implements loading of shared libraries/DLLs and their symb
|
||||
The behaviour of dynamically loaded libraries is specific to the target platform of the program.
|
||||
For in depth detail on the underlying behaviour please refer to your target platform's documentation.
|
||||
|
||||
See `example` directory for an example library exporting 3 symbols and a host program loading them automatically
|
||||
by defining a symbol table struct.
|
||||
For a full example, see: [[ core/dynlib/example; https://github.com/odin-lang/Odin/tree/master/core/dynlib/example ]]
|
||||
*/
|
||||
package dynlib
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//+build js
|
||||
//+private
|
||||
#+build js
|
||||
#+private
|
||||
package dynlib
|
||||
|
||||
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//+build linux, darwin, freebsd, openbsd, netbsd
|
||||
//+private
|
||||
#+build linux, darwin, freebsd, openbsd, netbsd
|
||||
#+private
|
||||
package dynlib
|
||||
|
||||
import "core:os"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//+build windows
|
||||
//+private
|
||||
#+build windows
|
||||
#+private
|
||||
package dynlib
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
|
||||
@@ -13,8 +13,8 @@ If your terminal supports 24-bit true color mode, you can also do this:
|
||||
fmt.println(ansi.CSI + ansi.FG_COLOR_24_BIT + ";0;255;255" + ansi.SGR + "Hellope!" + ansi.CSI + ansi.RESET + ansi.SGR)
|
||||
|
||||
For more information, see:
|
||||
1. https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
2. https://www.vt100.net/docs/vt102-ug/chapter5.html
|
||||
3. https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
- [[ https://en.wikipedia.org/wiki/ANSI_escape_code ]]
|
||||
- [[ https://www.vt100.net/docs/vt102-ug/chapter5.html ]]
|
||||
- [[ https://invisible-island.net/xterm/ctlseqs/ctlseqs.html ]]
|
||||
*/
|
||||
package ansi
|
||||
|
||||
@@ -675,10 +675,6 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header,
|
||||
return
|
||||
|
||||
case reflect.Type_Info_Map:
|
||||
if !reflect.is_string(t.key) {
|
||||
return _unsupported(v, hdr)
|
||||
}
|
||||
|
||||
raw_map := (^mem.Raw_Map)(v.data)
|
||||
if raw_map.allocator.procedure == nil {
|
||||
raw_map.allocator = context.allocator
|
||||
@@ -695,43 +691,31 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header,
|
||||
new_len := uintptr(min(scap, runtime.map_len(raw_map^)+length))
|
||||
runtime.map_reserve_dynamic(raw_map, t.map_info, new_len) or_return
|
||||
}
|
||||
|
||||
// Temporary memory to unmarshal keys into before inserting them into the map.
|
||||
|
||||
// Temporary memory to unmarshal values into before inserting them into the map.
|
||||
elem_backing := mem.alloc_bytes_non_zeroed(t.value.size, t.value.align, context.temp_allocator) or_return
|
||||
defer delete(elem_backing, context.temp_allocator)
|
||||
|
||||
map_backing_value := any{raw_data(elem_backing), t.value.id}
|
||||
|
||||
for idx := 0; unknown || idx < length; idx += 1 {
|
||||
// Decode key, keys can only be strings.
|
||||
key: string
|
||||
if keyv, kerr := decode_key(d, v); unknown && kerr == .Break {
|
||||
break
|
||||
} else if kerr != nil {
|
||||
err = kerr
|
||||
return
|
||||
} else {
|
||||
key = keyv
|
||||
}
|
||||
// Temporary memory to unmarshal keys into.
|
||||
key_backing := mem.alloc_bytes_non_zeroed(t.key.size, t.key.align, context.temp_allocator) or_return
|
||||
defer delete(key_backing, context.temp_allocator)
|
||||
key_backing_value := any{raw_data(key_backing), t.key.id}
|
||||
|
||||
for idx := 0; unknown || idx < length; idx += 1 {
|
||||
if unknown || idx > scap {
|
||||
// Reserve space for new element so we can return allocator errors.
|
||||
new_len := uintptr(runtime.map_len(raw_map^)+1)
|
||||
runtime.map_reserve_dynamic(raw_map, t.map_info, new_len) or_return
|
||||
}
|
||||
|
||||
mem.zero_slice(key_backing)
|
||||
_unmarshal_value(d, key_backing_value, _decode_header(r) or_return) or_return
|
||||
|
||||
mem.zero_slice(elem_backing)
|
||||
_unmarshal_value(d, map_backing_value, _decode_header(r) or_return) or_return
|
||||
|
||||
key_ptr := rawptr(&key)
|
||||
key_cstr: cstring
|
||||
if reflect.is_cstring(t.key) {
|
||||
assert_safe_for_cstring(key)
|
||||
key_cstr = cstring(raw_data(key))
|
||||
key_ptr = &key_cstr
|
||||
}
|
||||
|
||||
set_ptr := runtime.__dynamic_map_set_without_hash(raw_map, t.map_info, key_ptr, map_backing_value.data)
|
||||
set_ptr := runtime.__dynamic_map_set_without_hash(raw_map, t.map_info, key_backing_value.data, map_backing_value.data)
|
||||
// We already reserved space for it, so this shouldn't fail.
|
||||
assert(set_ptr != nil)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
package csv reads and writes comma-separated values (CSV) files.
|
||||
This package supports the format described in [[ RFC 4180; https://tools.ietf.org/html/rfc4180.html ]]
|
||||
|
||||
Example:
|
||||
package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:encoding/csv"
|
||||
import "core:os"
|
||||
|
||||
// Requires keeping the entire CSV file in memory at once
|
||||
iterate_csv_from_string :: proc(filename: string) {
|
||||
r: csv.Reader
|
||||
r.trim_leading_space = true
|
||||
r.reuse_record = true // Without it you have to delete(record)
|
||||
r.reuse_record_buffer = true // Without it you have to each of the fields within it
|
||||
defer csv.reader_destroy(&r)
|
||||
|
||||
csv_data, ok := os.read_entire_file(filename)
|
||||
if ok {
|
||||
csv.reader_init_with_string(&r, string(csv_data))
|
||||
} else {
|
||||
fmt.printfln("Unable to open file: %v", filename)
|
||||
return
|
||||
}
|
||||
defer delete(csv_data)
|
||||
|
||||
for r, i, err in csv.iterator_next(&r) {
|
||||
if err != nil { /* Do something with error */ }
|
||||
for f, j in r {
|
||||
fmt.printfln("Record %v, field %v: %q", i, j, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the CSV as it's processed (with a small buffer)
|
||||
iterate_csv_from_stream :: proc(filename: string) {
|
||||
fmt.printfln("Hellope from %v", filename)
|
||||
r: csv.Reader
|
||||
r.trim_leading_space = true
|
||||
r.reuse_record = true // Without it you have to delete(record)
|
||||
r.reuse_record_buffer = true // Without it you have to each of the fields within it
|
||||
defer csv.reader_destroy(&r)
|
||||
|
||||
handle, err := os.open(filename)
|
||||
if err != nil {
|
||||
fmt.eprintfln("Error opening file: %v", filename)
|
||||
return
|
||||
}
|
||||
defer os.close(handle)
|
||||
csv.reader_init(&r, os.stream_from_handle(handle))
|
||||
|
||||
for r, i in csv.iterator_next(&r) {
|
||||
for f, j in r {
|
||||
fmt.printfln("Record %v, field %v: %q", i, j, f)
|
||||
}
|
||||
}
|
||||
fmt.printfln("Error: %v", csv.iterator_last_error(r))
|
||||
}
|
||||
|
||||
// Read all records at once
|
||||
read_csv_from_string :: proc(filename: string) {
|
||||
r: csv.Reader
|
||||
r.trim_leading_space = true
|
||||
r.reuse_record = true // Without it you have to delete(record)
|
||||
r.reuse_record_buffer = true // Without it you have to each of the fields within it
|
||||
defer csv.reader_destroy(&r)
|
||||
|
||||
csv_data, ok := os.read_entire_file(filename)
|
||||
if ok {
|
||||
csv.reader_init_with_string(&r, string(csv_data))
|
||||
} else {
|
||||
fmt.printfln("Unable to open file: %v", filename)
|
||||
return
|
||||
}
|
||||
defer delete(csv_data)
|
||||
|
||||
records, err := csv.read_all(&r)
|
||||
if err != nil { /* Do something with CSV parse error */ }
|
||||
|
||||
defer {
|
||||
for rec in records {
|
||||
delete(rec)
|
||||
}
|
||||
delete(records)
|
||||
}
|
||||
|
||||
for r, i in records {
|
||||
for f, j in r {
|
||||
fmt.printfln("Record %v, field %v: %q", i, j, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
package encoding_csv
|
||||
@@ -1,88 +0,0 @@
|
||||
//+build ignore
|
||||
package encoding_csv
|
||||
|
||||
import "core:fmt"
|
||||
import "core:encoding/csv"
|
||||
import "core:os"
|
||||
|
||||
// Requires keeping the entire CSV file in memory at once
|
||||
iterate_csv_from_string :: proc(filename: string) {
|
||||
r: csv.Reader
|
||||
r.trim_leading_space = true
|
||||
r.reuse_record = true // Without it you have to delete(record)
|
||||
r.reuse_record_buffer = true // Without it you have to each of the fields within it
|
||||
defer csv.reader_destroy(&r)
|
||||
|
||||
if csv_data, ok := os.read_entire_file(filename); ok {
|
||||
csv.reader_init_with_string(&r, string(csv_data))
|
||||
defer delete(csv_data)
|
||||
} else {
|
||||
fmt.printfln("Unable to open file: %v", filename)
|
||||
return
|
||||
}
|
||||
|
||||
for r, i, err in csv.iterator_next(&r) {
|
||||
if err != nil { /* Do something with error */ }
|
||||
for f, j in r {
|
||||
fmt.printfln("Record %v, field %v: %q", i, j, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the CSV as it's processed (with a small buffer)
|
||||
iterate_csv_from_stream :: proc(filename: string) {
|
||||
fmt.printfln("Hellope from %v", filename)
|
||||
r: csv.Reader
|
||||
r.trim_leading_space = true
|
||||
r.reuse_record = true // Without it you have to delete(record)
|
||||
r.reuse_record_buffer = true // Without it you have to each of the fields within it
|
||||
defer csv.reader_destroy(&r)
|
||||
|
||||
handle, err := os.open(filename)
|
||||
if err != nil {
|
||||
fmt.eprintfln("Error opening file: %v", filename)
|
||||
return
|
||||
}
|
||||
defer os.close(handle)
|
||||
csv.reader_init(&r, os.stream_from_handle(handle))
|
||||
|
||||
for r, i in csv.iterator_next(&r) {
|
||||
for f, j in r {
|
||||
fmt.printfln("Record %v, field %v: %q", i, j, f)
|
||||
}
|
||||
}
|
||||
fmt.printfln("Error: %v", csv.iterator_last_error(r))
|
||||
}
|
||||
|
||||
// Read all records at once
|
||||
read_csv_from_string :: proc(filename: string) {
|
||||
r: csv.Reader
|
||||
r.trim_leading_space = true
|
||||
r.reuse_record = true // Without it you have to delete(record)
|
||||
r.reuse_record_buffer = true // Without it you have to each of the fields within it
|
||||
defer csv.reader_destroy(&r)
|
||||
|
||||
if csv_data, ok := os.read_entire_file(filename); ok {
|
||||
csv.reader_init_with_string(&r, string(csv_data))
|
||||
defer delete(csv_data)
|
||||
} else {
|
||||
fmt.printfln("Unable to open file: %v", filename)
|
||||
return
|
||||
}
|
||||
|
||||
records, err := csv.read_all(&r)
|
||||
if err != nil { /* Do something with CSV parse error */ }
|
||||
|
||||
defer {
|
||||
for rec in records {
|
||||
delete(rec)
|
||||
}
|
||||
delete(records)
|
||||
}
|
||||
|
||||
for r, i in records {
|
||||
for f, j in r {
|
||||
fmt.printfln("Record %v, field %v: %q", i, j, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// package csv reads and writes comma-separated values (CSV) files.
|
||||
// This package supports the format described in RFC 4180 <https://tools.ietf.org/html/rfc4180.html>
|
||||
// This package supports the format described in [[ RFC 4180; https://tools.ietf.org/html/rfc4180.html ]]
|
||||
package encoding_csv
|
||||
|
||||
import "core:bufio"
|
||||
@@ -484,4 +484,4 @@ _read_record :: proc(r: ^Reader, dst: ^[dynamic]string, allocator := context.all
|
||||
r.fields_per_record = len(dst)
|
||||
}
|
||||
return dst[:], err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,23 @@
|
||||
Package endian implements a simple translation between bytes and numbers with
|
||||
specific endian encodings.
|
||||
|
||||
buf: [100]u8
|
||||
put_u16(buf[:], .Little, 16) or_return
|
||||
Example:
|
||||
buf: [100]u8
|
||||
put_u16(buf[:], .Little, 16) or_return
|
||||
|
||||
You may ask yourself, why isn't `byte_order` platform Endianness by default, so we can write:
|
||||
put_u16(buf[:], 16) or_return
|
||||
// You may ask yourself, why isn't `byte_order` platform Endianness by default, so we can write:
|
||||
put_u16(buf[:], 16) or_return
|
||||
|
||||
The answer is that very few file formats are written in native/platform endianness. Most of them specify the endianness of
|
||||
each of their fields, or use a header field which specifies it for the entire file.
|
||||
// The answer is that very few file formats are written in native/platform endianness. Most of them specify the endianness of
|
||||
// each of their fields, or use a header field which specifies it for the entire file.
|
||||
|
||||
e.g. a file which specifies it at the top for all fields could do this:
|
||||
file_order := .Little if buf[0] == 0 else .Big
|
||||
field := get_u16(buf[1:], file_order) or_return
|
||||
// e.g. a file which specifies it at the top for all fields could do this:
|
||||
file_order := .Little if buf[0] == 0 else .Big
|
||||
field := get_u16(buf[1:], file_order) or_return
|
||||
|
||||
If on the other hand a field is *always* Big-Endian, you're wise to explicitly state it for the benefit of the reader,
|
||||
be that your future self or someone else.
|
||||
// If on the other hand a field is *always* Big-Endian, you're wise to explicitly state it for the benefit of the reader,
|
||||
// be that your future self or someone else.
|
||||
|
||||
field := get_u16(buf[:], .Big) or_return
|
||||
field := get_u16(buf[:], .Big) or_return
|
||||
*/
|
||||
package encoding_endian
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
package encoding_unicode_entity
|
||||
/*
|
||||
A unicode entity encoder/decoder
|
||||
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
This code has several procedures to map unicode runes to/from different textual encodings.
|
||||
- SGML/XML/HTML entity
|
||||
-- &#<decimal>;
|
||||
-- &#x<hexadecimal>;
|
||||
-- &<entity name>; (If the lookup tables are compiled in).
|
||||
Reference: https://www.w3.org/2003/entities/2007xml/unicode.xml
|
||||
|
||||
- URL encode / decode %hex entity
|
||||
Reference: https://datatracker.ietf.org/doc/html/rfc3986/#section-2.1
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
A unicode entity encoder/decoder.
|
||||
|
||||
This code has several procedures to map unicode runes to/from different textual encodings.
|
||||
- SGML/XML/HTML entity
|
||||
- &#<decimal>;
|
||||
- &#x<hexadecimal>;
|
||||
- &<entity name>; (If the lookup tables are compiled in).
|
||||
Reference: [[ https://www.w3.org/2003/entities/2007xml/unicode.xml ]]
|
||||
|
||||
- URL encode / decode %hex entity
|
||||
Reference: [[ https://datatracker.ietf.org/doc/html/rfc3986/#section-2.1 ]]
|
||||
*/
|
||||
package encoding_unicode_entity
|
||||
|
||||
import "core:unicode/utf8"
|
||||
import "core:unicode"
|
||||
import "core:strings"
|
||||
@@ -353,4 +355,4 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X
|
||||
|
||||
}
|
||||
return false, .None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ XML_NAME_TO_RUNE_MAX_LENGTH :: 31
|
||||
Input:
|
||||
entity_name - a string, like "copy" that describes a user-encoded Unicode entity as used in XML.
|
||||
|
||||
Output:
|
||||
Returns:
|
||||
"decoded" - The decoded rune if found by name, or -1 otherwise.
|
||||
"ok" - true if found, false if not.
|
||||
|
||||
|
||||
+89
-83
@@ -1,83 +1,89 @@
|
||||
// Implementation of the HxA 3D asset format
|
||||
// HxA is a interchangeable graphics asset format.
|
||||
// Designed by Eskil Steenberg. @quelsolaar / eskil 'at' obsession 'dot' se / www.quelsolaar.com
|
||||
//
|
||||
// Author of this Odin package: Ginger Bill
|
||||
//
|
||||
// Following comment is copied from the original C-implementation
|
||||
// ---------
|
||||
// -Does the world need another Graphics file format?
|
||||
// Unfortunately, Yes. All existing formats are either too large and complicated to be implemented from
|
||||
// scratch, or don't have some basic features needed in modern computer graphics.
|
||||
// -Who is this format for?
|
||||
// For people who want a capable open Graphics format that can be implemented from scratch in
|
||||
// a few hours. It is ideal for graphics researchers, game developers or other people who
|
||||
// wants to build custom graphics pipelines. Given how easy it is to parse and write, it
|
||||
// should be easy to write utilities that process assets to preform tasks like: generating
|
||||
// normals, light-maps, tangent spaces, Error detection, GPU optimization, LOD generation,
|
||||
// and UV mapping.
|
||||
// -Why store images in the format when there are so many good image formats already?
|
||||
// Yes there are, but only for 2D RGB/RGBA images. A lot of computer graphics rendering rely
|
||||
// on 1D, 3D, cube, multilayer, multi channel, floating point bitmap buffers. There almost no
|
||||
// formats for this kind of data. Also 3D files that reference separate image files rely on
|
||||
// file paths, and this often creates issues when the assets are moved. By including the
|
||||
// texture data in the files directly the assets become self contained.
|
||||
// -Why doesn't the format support <insert whatever>?
|
||||
// Because the entire point is to make a format that can be implemented. Features like NURBSs,
|
||||
// Construction history, or BSP trees would make the format too large to serve its purpose.
|
||||
// The facilities of the formats to store meta data should make the format flexible enough
|
||||
// for most uses. Adding HxA support should be something anyone can do in a days work.
|
||||
//
|
||||
// Structure:
|
||||
// ----------
|
||||
// HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has
|
||||
// a few basic structures, and depending on how they are used they mean different things. This means
|
||||
// that you can implement a tool that loads the entire file, modifies the parts it cares about and
|
||||
// leaves the rest intact. It is also possible to write a tool that makes all data in the file
|
||||
// editable without the need to understand its use. It is also possible for anyone to use the format
|
||||
// to store data axillary data. Anyone who wants to store data not covered by a convention can submit
|
||||
// a convention to extend the format. There should never be a convention for storing the same data in
|
||||
// two differed ways.
|
||||
// The data is story in a number of nodes that are stored in an array. Each node stores an array of
|
||||
// meta data. Meta data can describe anything you want, and a lot of conventions will use meta data
|
||||
// to store additional information, for things like transforms, lights, shaders and animation.
|
||||
// Data for Vertices, Corners, Faces, and Pixels are stored in named layer stacks. Each stack consists
|
||||
// of a number of named layers. All layers in the stack have the same number of elements. Each layer
|
||||
// describes one property of the primitive. Each layer can have multiple channels and each layer can
|
||||
// store data of a different type.
|
||||
//
|
||||
// HaX stores 3 kinds of nodes
|
||||
// - Pixel data.
|
||||
// - Polygon geometry data.
|
||||
// - Meta data only.
|
||||
//
|
||||
// Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness,
|
||||
// Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the
|
||||
// layers to store things like color. The length of the layer stack is determined by the type and
|
||||
// dimensions stored in the
|
||||
//
|
||||
// Geometry data is stored in 3 separate layer stacks for: vertex data, corner data and face data. The
|
||||
// vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first
|
||||
// layer in a vertex stack has to be a 3 channel layer named "position" describing the base position
|
||||
// of the vertices. The corner stack describes data per corner or edge of the polygons. It can be used
|
||||
// for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel
|
||||
// integer layer named "index" describing the vertices used to form polygons. The last value in each
|
||||
// polygon has a negative - 1 index to indicate the end of the polygon.
|
||||
//
|
||||
// Example:
|
||||
// A quad and a tri with the vertex index:
|
||||
// [0, 1, 2, 3] [1, 4, 2]
|
||||
// is stored:
|
||||
// [0, 1, 2, -4, 1, 4, -3]
|
||||
// The face stack stores values per face. the length of the face stack has to match the number of
|
||||
// negative values in the index layer in the corner stack. The face stack can be used to store things
|
||||
// like material index.
|
||||
//
|
||||
// Storage
|
||||
// -------
|
||||
// All data is stored in little endian byte order with no padding. The layout mirrors the structs
|
||||
// defined below with a few exceptions. All names are stored as a 8-bit unsigned integer indicating
|
||||
// the length of the name followed by that many characters. Termination is not stored in the file.
|
||||
// Text strings stored in meta data are stored the same way as names, but instead of a 8-bit unsigned
|
||||
// integer a 32-bit unsigned integer is used.
|
||||
package encoding_hxa
|
||||
/*
|
||||
Implementation of the HxA 3D asset format
|
||||
HxA is a interchangeable graphics asset format.
|
||||
Designed by Eskil Steenberg. @quelsolaar / eskil 'at' obsession 'dot' se / www.quelsolaar.com
|
||||
|
||||
Author of this Odin package: Ginger Bill
|
||||
|
||||
Following comment is copied from the original C-implementation
|
||||
---------
|
||||
- Does the world need another Graphics file format?
|
||||
Unfortunately, Yes. All existing formats are either too large and complicated to be implemented from
|
||||
scratch, or don't have some basic features needed in modern computer graphics.
|
||||
|
||||
- Who is this format for?
|
||||
For people who want a capable open Graphics format that can be implemented from scratch in
|
||||
a few hours. It is ideal for graphics researchers, game developers or other people who
|
||||
wants to build custom graphics pipelines. Given how easy it is to parse and write, it
|
||||
should be easy to write utilities that process assets to preform tasks like: generating
|
||||
normals, light-maps, tangent spaces, Error detection, GPU optimization, LOD generation,
|
||||
and UV mapping.
|
||||
|
||||
- Why store images in the format when there are so many good image formats already?
|
||||
Yes there are, but only for 2D RGB/RGBA images. A lot of computer graphics rendering rely
|
||||
on 1D, 3D, cube, multilayer, multi channel, floating point bitmap buffers. There almost no
|
||||
formats for this kind of data. Also 3D files that reference separate image files rely on
|
||||
file paths, and this often creates issues when the assets are moved. By including the
|
||||
texture data in the files directly the assets become self contained.
|
||||
|
||||
- Why doesn't the format support <insert whatever>?
|
||||
Because the entire point is to make a format that can be implemented. Features like NURBSs,
|
||||
Construction history, or BSP trees would make the format too large to serve its purpose.
|
||||
The facilities of the formats to store meta data should make the format flexible enough
|
||||
for most uses. Adding HxA support should be something anyone can do in a days work.
|
||||
|
||||
Structure:
|
||||
----------
|
||||
HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has
|
||||
a few basic structures, and depending on how they are used they mean different things. This means
|
||||
that you can implement a tool that loads the entire file, modifies the parts it cares about and
|
||||
leaves the rest intact. It is also possible to write a tool that makes all data in the file
|
||||
editable without the need to understand its use. It is also possible for anyone to use the format
|
||||
to store data axillary data. Anyone who wants to store data not covered by a convention can submit
|
||||
a convention to extend the format. There should never be a convention for storing the same data in
|
||||
two differed ways.
|
||||
|
||||
The data is story in a number of nodes that are stored in an array. Each node stores an array of
|
||||
meta data. Meta data can describe anything you want, and a lot of conventions will use meta data
|
||||
to store additional information, for things like transforms, lights, shaders and animation.
|
||||
Data for Vertices, Corners, Faces, and Pixels are stored in named layer stacks. Each stack consists
|
||||
of a number of named layers. All layers in the stack have the same number of elements. Each layer
|
||||
describes one property of the primitive. Each layer can have multiple channels and each layer can
|
||||
store data of a different type.
|
||||
|
||||
HaX stores 3 kinds of nodes
|
||||
- Pixel data.
|
||||
- Polygon geometry data.
|
||||
- Meta data only.
|
||||
|
||||
Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness,
|
||||
Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the
|
||||
layers to store things like color.
|
||||
The length of the layer stack is determined by the type and dimensions stored in the Geometry data
|
||||
is stored in 3 separate layer stacks for: vertex data, corner data and face data. The
|
||||
vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first
|
||||
layer in a vertex stack has to be a 3 channel layer named "position" describing the base position
|
||||
of the vertices. The corner stack describes data per corner or edge of the polygons. It can be used
|
||||
for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel
|
||||
integer layer named "index" describing the vertices used to form polygons. The last value in each
|
||||
polygon has a negative - 1 index to indicate the end of the polygon.
|
||||
|
||||
For Example:
|
||||
A quad and a tri with the vertex index:
|
||||
[0, 1, 2, 3] [1, 4, 2]
|
||||
is stored:
|
||||
[0, 1, 2, -4, 1, 4, -3]
|
||||
|
||||
The face stack stores values per face. the length of the face stack has to match the number of
|
||||
negative values in the index layer in the corner stack. The face stack can be used to store things
|
||||
like material index.
|
||||
|
||||
Storage:
|
||||
-------
|
||||
All data is stored in little endian byte order with no padding. The layout mirrors the structs
|
||||
defined below with a few exceptions. All names are stored as a 8-bit unsigned integer indicating
|
||||
the length of the name followed by that many characters. Termination is not stored in the file.
|
||||
Text strings stored in meta data are stored the same way as names, but instead of a 8-bit unsigned
|
||||
integer a 32-bit unsigned integer is used.
|
||||
*/
|
||||
package encoding_hxa
|
||||
|
||||
@@ -116,7 +116,30 @@ assign_int :: proc(val: any, i: $T) -> bool {
|
||||
case int: dst = int (i)
|
||||
case uint: dst = uint (i)
|
||||
case uintptr: dst = uintptr(i)
|
||||
case: return false
|
||||
case:
|
||||
ti := type_info_of(v.id)
|
||||
if _, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok {
|
||||
do_byte_swap := !reflect.bit_set_is_big_endian(v)
|
||||
switch ti.size * 8 {
|
||||
case 0: // no-op.
|
||||
case 8:
|
||||
x := (^u8)(v.data)
|
||||
x^ = u8(i)
|
||||
case 16:
|
||||
x := (^u16)(v.data)
|
||||
x^ = do_byte_swap ? intrinsics.byte_swap(u16(i)) : u16(i)
|
||||
case 32:
|
||||
x := (^u32)(v.data)
|
||||
x^ = do_byte_swap ? intrinsics.byte_swap(u32(i)) : u32(i)
|
||||
case 64:
|
||||
x := (^u64)(v.data)
|
||||
x^ = do_byte_swap ? intrinsics.byte_swap(u64(i)) : u64(i)
|
||||
case:
|
||||
panic("unknown bit_size size")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -21,8 +21,9 @@ cryptographically-secure, per RFC 9562's suggestion.
|
||||
- Version 6 without either a clock or node argument.
|
||||
- Version 7 in all cases.
|
||||
|
||||
Here's an example of how to set up one:
|
||||
|
||||
Example:
|
||||
package main
|
||||
|
||||
import "core:crypto"
|
||||
import "core:encoding/uuid"
|
||||
|
||||
@@ -40,7 +41,7 @@ Here's an example of how to set up one:
|
||||
|
||||
|
||||
For more information on the specifications, see here:
|
||||
- https://www.rfc-editor.org/rfc/rfc4122.html
|
||||
- https://www.rfc-editor.org/rfc/rfc9562.html
|
||||
- [[ https://www.rfc-editor.org/rfc/rfc4122.html ]]
|
||||
- [[ https://www.rfc-editor.org/rfc/rfc9562.html ]]
|
||||
*/
|
||||
package uuid
|
||||
|
||||
@@ -11,7 +11,7 @@ Write a UUID in the 8-4-4-4-12 format.
|
||||
This procedure performs error checking with every byte written.
|
||||
|
||||
If you can guarantee beforehand that your stream has enough space to hold the
|
||||
UUID (32 bytes), then it is better to use `unsafe_write` instead as that will
|
||||
UUID (36 bytes), then it is better to use `unsafe_write` instead as that will
|
||||
be faster.
|
||||
|
||||
Inputs:
|
||||
@@ -22,7 +22,7 @@ Returns:
|
||||
- error: An `io` error, if one occurred, otherwise `nil`.
|
||||
*/
|
||||
write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_check {
|
||||
write_octet :: proc (w: io.Writer, octet: u8) -> io.Error #no_bounds_check {
|
||||
write_octet :: proc(w: io.Writer, octet: u8) -> io.Error #no_bounds_check {
|
||||
high_nibble := octet >> 4
|
||||
low_nibble := octet & 0xF
|
||||
|
||||
@@ -31,15 +31,15 @@ write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_chec
|
||||
return nil
|
||||
}
|
||||
|
||||
for index in 0 ..< 4 { write_octet(w, id[index]) or_return }
|
||||
for index in 0 ..< 4 {write_octet(w, id[index]) or_return}
|
||||
io.write_byte(w, '-') or_return
|
||||
for index in 4 ..< 6 { write_octet(w, id[index]) or_return }
|
||||
for index in 4 ..< 6 {write_octet(w, id[index]) or_return}
|
||||
io.write_byte(w, '-') or_return
|
||||
for index in 6 ..< 8 { write_octet(w, id[index]) or_return }
|
||||
for index in 6 ..< 8 {write_octet(w, id[index]) or_return}
|
||||
io.write_byte(w, '-') or_return
|
||||
for index in 8 ..< 10 { write_octet(w, id[index]) or_return }
|
||||
for index in 8 ..< 10 {write_octet(w, id[index]) or_return}
|
||||
io.write_byte(w, '-') or_return
|
||||
for index in 10 ..< 16 { write_octet(w, id[index]) or_return }
|
||||
for index in 10 ..< 16 {write_octet(w, id[index]) or_return}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -54,7 +54,7 @@ Inputs:
|
||||
- id: The identifier to convert.
|
||||
*/
|
||||
unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
|
||||
write_octet :: proc (w: io.Writer, octet: u8) #no_bounds_check {
|
||||
write_octet :: proc(w: io.Writer, octet: u8) #no_bounds_check {
|
||||
high_nibble := octet >> 4
|
||||
low_nibble := octet & 0xF
|
||||
|
||||
@@ -62,15 +62,15 @@ unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
|
||||
io.write_byte(w, strconv.digits[low_nibble])
|
||||
}
|
||||
|
||||
for index in 0 ..< 4 { write_octet(w, id[index]) }
|
||||
for index in 0 ..< 4 {write_octet(w, id[index])}
|
||||
io.write_byte(w, '-')
|
||||
for index in 4 ..< 6 { write_octet(w, id[index]) }
|
||||
for index in 4 ..< 6 {write_octet(w, id[index])}
|
||||
io.write_byte(w, '-')
|
||||
for index in 6 ..< 8 { write_octet(w, id[index]) }
|
||||
for index in 6 ..< 8 {write_octet(w, id[index])}
|
||||
io.write_byte(w, '-')
|
||||
for index in 8 ..< 10 { write_octet(w, id[index]) }
|
||||
for index in 8 ..< 10 {write_octet(w, id[index])}
|
||||
io.write_byte(w, '-')
|
||||
for index in 10 ..< 16 { write_octet(w, id[index]) }
|
||||
for index in 10 ..< 16 {write_octet(w, id[index])}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,7 +106,7 @@ Convert a UUID to a string in the 8-4-4-4-12 format.
|
||||
|
||||
Inputs:
|
||||
- id: The identifier to convert.
|
||||
- buffer: A byte buffer to store the result. Must be at least 32 bytes large.
|
||||
- buffer: A byte buffer to store the result. Must be at least 36 bytes large.
|
||||
- loc: The caller location for debugging purposes (default: #caller_location)
|
||||
|
||||
Returns:
|
||||
@@ -119,7 +119,11 @@ to_string_buffer :: proc(
|
||||
) -> (
|
||||
str: string,
|
||||
) {
|
||||
assert(len(buffer) >= EXPECTED_LENGTH, "The buffer provided is not at least 32 bytes large.", loc)
|
||||
assert(
|
||||
len(buffer) >= EXPECTED_LENGTH,
|
||||
"The buffer provided is not at least 36 bytes large.",
|
||||
loc,
|
||||
)
|
||||
builder := strings.builder_from_bytes(buffer)
|
||||
unsafe_write(strings.to_writer(&builder), id)
|
||||
return strings.to_string(builder)
|
||||
@@ -129,3 +133,4 @@ to_string :: proc {
|
||||
to_string_allocated,
|
||||
to_string_buffer,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
Implementation of the LEB128 variable integer encoding as used by DWARF encoding and DEX files, among others.
|
||||
Implementation of the LEB128 variable integer encoding as used by DWARF encoding and DEX files, among others.
|
||||
|
||||
Author of this Odin package: Jeroen van Rijn
|
||||
Author of this Odin package: Jeroen van Rijn
|
||||
|
||||
Example:
|
||||
package main
|
||||
|
||||
Example:
|
||||
```odin
|
||||
import "core:encoding/varint"
|
||||
import "core:fmt"
|
||||
|
||||
@@ -22,7 +23,5 @@
|
||||
assert(decoded_val == value && decode_size == encode_size && decode_err == .None)
|
||||
fmt.printf("Decoded as %v, using %v byte%v\n", decoded_val, decode_size, "" if decode_size == 1 else "s")
|
||||
}
|
||||
```
|
||||
|
||||
*/
|
||||
package encoding_varint
|
||||
package encoding_varint
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
// package varint implements variable length integer encoding and decoding using
|
||||
// the LEB128 format as used by DWARF debug info, Android .dex and other file formats.
|
||||
package encoding_varint
|
||||
|
||||
// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file.
|
||||
@@ -160,4 +158,4 @@ encode_ileb128 :: proc(buf: []u8, val: i128) -> (size: int, err: Error) {
|
||||
buf[size - 1] = u8(low)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
XML 1.0 / 1.1 parser
|
||||
|
||||
A from-scratch XML implementation, loosely modelled on the [[ spec; https://www.w3.org/TR/2006/REC-xml11-20060816 ]].
|
||||
|
||||
Features:
|
||||
- Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage.
|
||||
- Simple to understand and use. Small.
|
||||
|
||||
Caveats:
|
||||
- We do NOT support HTML in this package, as that may or may not be valid XML.
|
||||
If it works, great. If it doesn't, that's not considered a bug.
|
||||
|
||||
- We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences.
|
||||
- <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options.
|
||||
|
||||
MAYBE:
|
||||
- XML writer?
|
||||
- Serialize/deserialize Odin types?
|
||||
|
||||
For a full example, see: [[ core/encoding/xml/example; https://github.com/odin-lang/Odin/tree/master/core/encoding/xml/example ]]
|
||||
*/
|
||||
package encoding_xml
|
||||
@@ -1,29 +1,11 @@
|
||||
/*
|
||||
XML 1.0 / 1.1 parser
|
||||
2021-2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||
available under Odin's BSD-3 license.
|
||||
|
||||
2021-2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||
available under Odin's BSD-3 license.
|
||||
|
||||
from-scratch XML implementation, loosely modelled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816).
|
||||
|
||||
Features:
|
||||
- Supports enough of the XML 1.0/1.1 spec to handle the 99.9% of XML documents in common current usage.
|
||||
- Simple to understand and use. Small.
|
||||
|
||||
Caveats:
|
||||
- We do NOT support HTML in this package, as that may or may not be valid XML.
|
||||
If it works, great. If it doesn't, that's not considered a bug.
|
||||
|
||||
- We do NOT support UTF-16. If you have a UTF-16 XML file, please convert it to UTF-8 first. Also, our condolences.
|
||||
- <[!ELEMENT and <[!ATTLIST are not supported, and will be either ignored or return an error depending on the parser options.
|
||||
|
||||
MAYBE:
|
||||
- XML writer?
|
||||
- Serialize/deserialize Odin types?
|
||||
|
||||
List of contributors:
|
||||
- Jeroen van Rijn: Initial implementation.
|
||||
List of contributors:
|
||||
- Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
package encoding_xml
|
||||
// An XML 1.0 / 1.1 parser
|
||||
|
||||
|
||||
+15
-25
@@ -11,15 +11,13 @@ Command-Line Syntax:
|
||||
Arguments are treated differently depending on how they're formatted.
|
||||
The format is similar to the Odin binary's way of handling compiler flags.
|
||||
|
||||
```
|
||||
type handling
|
||||
------------ ------------------------
|
||||
<positional> depends on struct layout
|
||||
-<flag> set a bool true
|
||||
-<flag:option> set flag to option
|
||||
-<flag=option> set flag to option, alternative syntax
|
||||
-<map>:<key>=<value> set map[key] to value
|
||||
```
|
||||
type handling
|
||||
------------ ------------------------
|
||||
<positional> depends on struct layout
|
||||
-<flag> set a bool true
|
||||
-<flag:option> set flag to option
|
||||
-<flag=option> set flag to option, alternative syntax
|
||||
-<map>:<key>=<value> set map[key] to value
|
||||
|
||||
|
||||
Struct Tags:
|
||||
@@ -40,11 +38,9 @@ Under the `args` tag, there are the following subtags:
|
||||
- `indistinct`: allow the setting of distinct types by their base type.
|
||||
|
||||
`required` may be given a range specifier in the following formats:
|
||||
```
|
||||
min
|
||||
<max
|
||||
min<max
|
||||
```
|
||||
min
|
||||
<max
|
||||
min<max
|
||||
|
||||
`max` is not inclusive in this range, as noted by the less-than `<` sign, so if
|
||||
you want to require 3 and only 3 arguments in a dynamic array, you would
|
||||
@@ -161,21 +157,15 @@ UNIX-style:
|
||||
This package also supports parsing arguments in a limited flavor of UNIX.
|
||||
Odin and UNIX style are mutually exclusive, and which one to be used is chosen
|
||||
at parse time.
|
||||
|
||||
```
|
||||
--flag
|
||||
--flag=argument
|
||||
--flag argument
|
||||
--flag argument repeating-argument
|
||||
```
|
||||
--flag
|
||||
--flag=argument
|
||||
--flag argument
|
||||
--flag argument repeating-argument
|
||||
|
||||
`-flag` may also be substituted for `--flag`.
|
||||
|
||||
Do note that map flags are not currently supported in this parsing style.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
A complete example is given in the `example` subdirectory.
|
||||
For a complete example, see: [[ core/flags/example; https://github.com/odin-lang/Odin/blob/master/core/flags/example/example.odin ]].
|
||||
*/
|
||||
package flags
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build netbsd, openbsd
|
||||
#+build netbsd, openbsd
|
||||
package flags
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//+build !netbsd !openbsd
|
||||
#+build !netbsd
|
||||
#+build !openbsd
|
||||
package flags
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+private
|
||||
#+private
|
||||
package flags
|
||||
|
||||
import "base:intrinsics"
|
||||
@@ -14,10 +14,10 @@ import "core:reflect"
|
||||
// positionals first before adding it to a fallback field.
|
||||
@(optimization_mode="favor_size")
|
||||
push_positional :: #force_no_inline proc (model: ^$T, parser: ^Parser, arg: string) -> (error: Error) {
|
||||
if bit_array.get(&parser.filled_pos, parser.filled_pos.max_index) {
|
||||
// The max index is set, which means we're out of space.
|
||||
if set, valid_index := bit_array.get(&parser.filled_pos, parser.filled_pos.length - 1); set || !valid_index {
|
||||
// The index below the last one is either set or invalid, which means we're out of space.
|
||||
// Add one free bit by setting the index above to false.
|
||||
bit_array.set(&parser.filled_pos, 1 + parser.filled_pos.max_index, false)
|
||||
bit_array.set(&parser.filled_pos, parser.filled_pos.length, false)
|
||||
}
|
||||
|
||||
pos: int = ---
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+private
|
||||
#+private
|
||||
package flags
|
||||
|
||||
import "core:container/bit_array"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+private
|
||||
#+private
|
||||
package flags
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//+private
|
||||
//+build !netbsd !openbsd
|
||||
#+private
|
||||
#+build !netbsd
|
||||
#+build !openbsd
|
||||
package flags
|
||||
|
||||
import "core:net"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+private
|
||||
#+private
|
||||
package flags
|
||||
|
||||
@require import "base:runtime"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build ignore
|
||||
#+build ignore
|
||||
package custom_formatter_example
|
||||
import "core:fmt"
|
||||
import "core:io"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build js
|
||||
#+build js
|
||||
package fmt
|
||||
|
||||
import "core:bufio"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//+build !freestanding
|
||||
//+build !js
|
||||
//+build !orca
|
||||
#+build !freestanding
|
||||
#+build !js
|
||||
#+build !orca
|
||||
package fmt
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/*
|
||||
An implementation of Yann Collet's [xxhash Fast Hash Algorithm](https://cyan4973.github.io/xxHash/).
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
|
||||
Made available under Odin's BSD-3 license, based on the original C code.
|
||||
@@ -7,6 +6,8 @@
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
// An implementation of Yann Collet's [[ xxhash Fast Hash Algorithm; https://cyan4973.github.io/xxHash/ ]].
|
||||
package xxhash
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
package xxhash
|
||||
|
||||
import "core:mem"
|
||||
@@ -371,4 +372,4 @@ XXH3_generate_secret :: proc(secret_buffer: []u8, custom_seed: []u8) {
|
||||
mem_copy(&secret_buffer[segment_start], &segment, size_of(segment))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
package xxhash
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
package xxhash
|
||||
|
||||
import "base:intrinsics"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
package xxhash
|
||||
|
||||
import "base:intrinsics"
|
||||
@@ -19,15 +20,15 @@ xxh_u64 :: u64
|
||||
XXH64_DEFAULT_SEED :: XXH64_hash(0)
|
||||
|
||||
XXH64_state :: struct {
|
||||
total_len: XXH64_hash, /*!< Total length hashed. This is always 64-bit. */
|
||||
v1: XXH64_hash, /*!< First accumulator lane */
|
||||
v2: XXH64_hash, /*!< Second accumulator lane */
|
||||
v3: XXH64_hash, /*!< Third accumulator lane */
|
||||
v4: XXH64_hash, /*!< Fourth accumulator lane */
|
||||
mem64: [4]XXH64_hash, /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */
|
||||
memsize: XXH32_hash, /*!< Amount of data in @ref mem64 */
|
||||
reserved32: XXH32_hash, /*!< Reserved field, needed for padding anyways*/
|
||||
reserved64: XXH64_hash, /*!< Reserved field. Do not read or write to it, it may be removed. */
|
||||
total_len: XXH64_hash, /*!< Total length hashed. This is always 64-bit. */
|
||||
v1: XXH64_hash, /*!< First accumulator lane */
|
||||
v2: XXH64_hash, /*!< Second accumulator lane */
|
||||
v3: XXH64_hash, /*!< Third accumulator lane */
|
||||
v4: XXH64_hash, /*!< Fourth accumulator lane */
|
||||
mem64: [4]XXH64_hash, /*!< Internal buffer for partial reads. Treated as unsigned char[32]. */
|
||||
memsize: XXH32_hash, /*!< Amount of data in @ref mem64 */
|
||||
reserved32: XXH32_hash, /*!< Reserved field, needed for padding anyways*/
|
||||
reserved64: XXH64_hash, /*!< Reserved field. Do not read or write to it, it may be removed. */
|
||||
}
|
||||
|
||||
XXH64_canonical :: struct {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build js
|
||||
#+build js
|
||||
package core_image_bmp
|
||||
|
||||
load :: proc{load_from_bytes, load_from_context}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//+build !js
|
||||
#+build !js
|
||||
package core_image_bmp
|
||||
|
||||
import "core:os"
|
||||
|
||||
@@ -1393,6 +1393,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
|
||||
for p in inp {
|
||||
out[0].rgb = p.r // Gray component.
|
||||
out[0].a = p.g // Alpha component.
|
||||
out = out[1:]
|
||||
}
|
||||
|
||||
case:
|
||||
@@ -1417,6 +1418,7 @@ expand_grayscale :: proc(img: ^Image, allocator := context.allocator) -> (ok: bo
|
||||
for p in inp {
|
||||
out[0].rgb = p.r // Gray component.
|
||||
out[0].a = p.g // Alpha component.
|
||||
out = out[1:]
|
||||
}
|
||||
|
||||
case:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user