diff options
| author | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-11-01 14:09:04 +0100 |
|---|---|---|
| committer | Aldrik Ramaekers <aldrikboy@gmail.com> | 2025-11-01 14:09:04 +0100 |
| commit | a2918b9724a65ba147cfafc6bcf8d410a647330b (patch) | |
| tree | 3b8ca3ee934a239f458b889f06beb673fa32ffa4 /libs/anr/anr_sc.h | |
| parent | 9b8664daf17dac9efb1f4add9d00c562e4ddbf40 (diff) | |
export ui, localizations
Diffstat (limited to 'libs/anr/anr_sc.h')
| -rw-r--r-- | libs/anr/anr_sc.h | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/libs/anr/anr_sc.h b/libs/anr/anr_sc.h new file mode 100644 index 0000000..8283c5f --- /dev/null +++ b/libs/anr/anr_sc.h @@ -0,0 +1,287 @@ +/* +anr_sc.h - v0.1 - worst compression library you have ever seen. + +Do this: + #ifdef ANR_SC_IMPLEMENTATION +before you include this file in *one* C file to create the implementation. + +*/ + +#ifndef INCLUDE_ANR_SC_H +#define INCLUDE_ANR_SC_H + +#ifndef ANRSCDEF +#define ANRSCDEF extern +#endif + +#ifdef ANR_SC_DEBUG +#include <stdio.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#ifndef ANRSC_ASSERT +#include <assert.h> +#define ANRSC_ASSERT(x) assert(x) +#endif + +ANRSCDEF uint8_t* anr_sc_deflate(uint8_t* data, uint32_t length, uint32_t* out_length); +ANRSCDEF uint8_t* anr_sc_inflate(uint8_t* data, uint32_t length, uint32_t* out_length); + +#endif // INCLUDE_ANR_SC_H + +#ifdef ANR_SC_IMPLEMENTATION + +typedef struct +{ + uint8_t val; + uint32_t count; +} anr_sc_val; + +#define MAX_ENCODED_CHARS 16 +#define TABLE_SIZE MAX_ENCODED_CHARS + +int cmpfunc (const void * a, const void * b) { + return ( (*(anr_sc_val*)a).count - (*(anr_sc_val*)b).count ); +} + +uint8_t* anr_sc_inflate(uint8_t* data, uint32_t length, uint32_t* out_length) +{ + anr_sc_val table[TABLE_SIZE]; + for (int i = 0; i < TABLE_SIZE; i++) + { + table[i].val = data[i]; + } + + uint8_t* inflated = malloc(length*8); // ballpark + uint32_t inflated_cursor = 0; + + uint8_t current_block_table = 0; + uint8_t block_table_index = 8; + uint32_t read_cursor_offset = 0; + for (int i = TABLE_SIZE; i < length;) + { + if (block_table_index == 8) { + if (read_cursor_offset == 4) { + read_cursor_offset = 0; + i++; + } + + current_block_table = data[i++]; + block_table_index = 0; + continue; + } + + uint8_t is_halve = (current_block_table >> block_table_index) & 0x1; + if (read_cursor_offset == 0) + { + if (is_halve) + { + uint8_t table_index = (data[i] >> 4); + inflated[inflated_cursor++] = table[table_index].val; + read_cursor_offset = 4; + } + else + { + inflated[inflated_cursor++] = data[i]; + read_cursor_offset = 0; + i++; + } + } + else if (read_cursor_offset == 4) + { + if (is_halve) + { + uint8_t table_index = (data[i] & 0xF); + inflated[inflated_cursor++] = table[table_index].val; + + read_cursor_offset = 0; + i++; + } + else + { + uint8_t top = data[i] & 0xF; + uint8_t bottom = data[i+1] & 0xF0; + uint8_t val = (top << 4) | (bottom >> 4); + inflated[inflated_cursor++] = val; + + read_cursor_offset = 4; + i++; + } + } + + + block_table_index++; + } + + *out_length = inflated_cursor; + return inflated; +} + +uint8_t* anr_sc_deflate(uint8_t* data, uint32_t length, uint32_t* out_length) +{ + anr_sc_val values[256]; + for (uint32_t i = 0; i < 256; i++) + { + values[i].val = i; + values[i].count = 0; + } + + for (uint32_t i = 0; i < length; i++) + { + values[data[i]].count++; + } + qsort(values, 256, sizeof(anr_sc_val), cmpfunc); + + anr_sc_val table[TABLE_SIZE]; + memset(table, 0, sizeof(table)); + for (int i = 0; i < 256; i++) + { + if (values[i].count == 0) continue; + if (i < 256-MAX_ENCODED_CHARS) continue; + table[256-i-1] = values[i]; + } + + // Find index of last indexable byte. + uint32_t index_of_last_byte = 0; + for (uint32_t i = 0; i < length; i++) + { + for (uint8_t x = 0; x < MAX_ENCODED_CHARS; x++) { + if (table[x].count == 0) continue; + if (data[i] == table[x].val) { + index_of_last_byte = i; + } + } + } + + // Write encoding table. + uint32_t max_size = length + MAX_ENCODED_CHARS + (length/8); + uint8_t* deflated = malloc(max_size); + memset(deflated, 0, max_size); + uint32_t deflated_cursor = 0; + uint32_t deflate_cursor_offset = 0; + for (int i = 0; i < MAX_ENCODED_CHARS; i++) + { + deflated[deflated_cursor++] = table[i].val; + } + + uint8_t current_block_table = 0; + uint32_t bits_in_block = 8; + uint32_t current_block_index = 0; + for (int i = 0; i < length; i++) + { + if (bits_in_block == 8) { + bits_in_block = 0; + current_block_table = 0; + current_block_index = deflated_cursor; + deflated_cursor++; // Reserved for block table. + } + + uint8_t is_halve = 0; + if (i == index_of_last_byte) { + if (deflate_cursor_offset == 0) { + goto skip_last_halfbyte; + } + } + + for (uint8_t x = 0; x < MAX_ENCODED_CHARS; x++) { + if (data[i] == table[x].val) { + is_halve = 1; + + if (deflate_cursor_offset == 0) + { + deflated[deflated_cursor] = x << 4; + deflate_cursor_offset = 4; + } + else if (deflate_cursor_offset == 4) + { + deflated[deflated_cursor++] |= x; + deflate_cursor_offset = 0; + } + break; + } + } + + + skip_last_halfbyte: + if (!is_halve) + { + if (deflate_cursor_offset == 0) + { + deflated[deflated_cursor++] = data[i]; + } + else if (deflate_cursor_offset == 4) + { + uint8_t top = data[i] >> 4; + uint8_t bottom = data[i] << 4; + deflated[deflated_cursor++] |= top; + deflated[deflated_cursor] |= bottom; + } + } + + current_block_table |= (is_halve << bits_in_block); + bits_in_block++; + if (bits_in_block == 8 || i+1>= length) { + deflated[current_block_index] = current_block_table; + + if (deflate_cursor_offset == 4) { + deflate_cursor_offset = 0; + deflated_cursor++; + } + } + } + + #ifdef ANR_SC_DEBUG + printf(" Deflated (%.1f%%)\n", (float)deflated_cursor/length*100.0f); + #endif + + *out_length = deflated_cursor; + return deflated; +} + + +#endif // ANR_SC_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2024 Aldrik Ramaekers +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/
\ No newline at end of file |
