diff --git a/CMakeLists.txt b/CMakeLists.txt index 5939603..2b73cb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ set(SimpleArchiver_VERSION 1.0) set(SimpleArchiver_SOURCES src/main.c src/parser.c + src/helpers.c src/data_structures/linked_list.c src/data_structures/hash_map.c src/data_structures/priority_heap.c @@ -37,4 +38,5 @@ add_executable(test_datastructures add_executable(test_simplearchiver src/test.c src/parser.c + src/helpers.c ) diff --git a/cosmopolitan/Makefile b/cosmopolitan/Makefile index 25b0188..7ac2466 100644 --- a/cosmopolitan/Makefile +++ b/cosmopolitan/Makefile @@ -6,6 +6,7 @@ OUTDIR = out SOURCES = \ ../src/main.c \ ../src/parser.c \ + ../src/helpers.c \ ../src/algorithms/linear_congruential_gen.c \ ../src/data_structures/linked_list.c \ ../src/data_structures/hash_map.c \ @@ -14,6 +15,7 @@ SOURCES = \ HEADERS = \ ../src/parser.h \ ../src/parser_internal.h \ + ../src/helpers.h \ ../src/algorithms/linear_congruential_gen.h \ ../src/data_structures/linked_list.h \ ../src/data_structures/hash_map.h \ diff --git a/src/helpers.c b/src/helpers.c new file mode 100644 index 0000000..0007f20 --- /dev/null +++ b/src/helpers.c @@ -0,0 +1,56 @@ +/* + * Copyright 2024 Stephen Seo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * `helpers.c` is the source for helpful/utility functions. + */ + +#include "helpers.h" + +int simple_archiver_helper_is_big_endian(void) { + union { + unsigned int i; + char c[4]; + } bint = {0x01020304}; + + return bint.c[0] == 1 ? 1 : 0; +} + +void simple_archiver_helper_16_bit_be(unsigned short *value) { + if (simple_archiver_helper_is_big_endian() == 0) { + unsigned char c = ((unsigned char *)value)[0]; + ((unsigned char *)value)[0] = ((unsigned char *)value)[1]; + ((unsigned char *)value)[1] = c; + } +} + +void simple_archiver_helper_32_bit_be(unsigned int *value) { + if (simple_archiver_helper_is_big_endian() == 0) { + for (unsigned int i = 0; i < 2; ++i) { + unsigned char c = ((unsigned char *)value)[i]; + ((unsigned char *)value)[i] = ((unsigned char *)value)[3 - i]; + ((unsigned char *)value)[3 - i] = c; + } + } +} + +void simple_archiver_helper_64_bit_be(unsigned long long *value) { + if (simple_archiver_helper_is_big_endian() == 0) { + for (unsigned int i = 0; i < 4; ++i) { + unsigned char c = ((unsigned char *)value)[i]; + ((unsigned char *)value)[i] = ((unsigned char *)value)[7 - i]; + ((unsigned char *)value)[7 - i] = c; + } + } +} diff --git a/src/helpers.h b/src/helpers.h new file mode 100644 index 0000000..3089b33 --- /dev/null +++ b/src/helpers.h @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Stephen Seo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * `helpers.h` is the header for helpful/utility functions. + */ + +#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_ +#define SEODISPARATE_COM_SIMPLE_ARCHIVER_HELPERS_H_ + +/// Returns non-zero if this system is big-endian. +int simple_archiver_helper_is_big_endian(void); + +/// Swaps value from/to big-endian. Nop on big-endian systems. +void simple_archiver_helper_16_bit_be(unsigned short *value); + +/// Swaps value from/to big-endian. Nop on big-endian systems. +void simple_archiver_helper_32_bit_be(unsigned int *value); + +/// Swaps value from/to big-endian. Nop on big-endian systems. +void simple_archiver_helper_64_bit_be(unsigned long long *value); + +#endif diff --git a/src/test.c b/src/test.c index cf6cb4f..7f07097 100644 --- a/src/test.c +++ b/src/test.c @@ -20,6 +20,7 @@ #include #include +#include "helpers.h" #include "parser_internal.h" static int checks_checked = 0; @@ -109,6 +110,66 @@ int main(void) { simple_archiver_free_parsed(&parsed); } + // Test helpers. + { + // Only if system is little-endian. + if (simple_archiver_helper_is_big_endian() == 0) { + unsigned short u16 = 0x0102; + CHECK_TRUE(((unsigned char *)&u16)[0] == 2); + CHECK_TRUE(((unsigned char *)&u16)[1] == 1); + simple_archiver_helper_16_bit_be(&u16); + CHECK_TRUE(((unsigned char *)&u16)[0] == 1); + CHECK_TRUE(((unsigned char *)&u16)[1] == 2); + simple_archiver_helper_16_bit_be(&u16); + CHECK_TRUE(((unsigned char *)&u16)[0] == 2); + CHECK_TRUE(((unsigned char *)&u16)[1] == 1); + + unsigned int u32 = 0x01020304; + CHECK_TRUE(((unsigned char *)&u32)[0] == 4); + CHECK_TRUE(((unsigned char *)&u32)[1] == 3); + CHECK_TRUE(((unsigned char *)&u32)[2] == 2); + CHECK_TRUE(((unsigned char *)&u32)[3] == 1); + simple_archiver_helper_32_bit_be(&u32); + CHECK_TRUE(((unsigned char *)&u32)[0] == 1); + CHECK_TRUE(((unsigned char *)&u32)[1] == 2); + CHECK_TRUE(((unsigned char *)&u32)[2] == 3); + CHECK_TRUE(((unsigned char *)&u32)[3] == 4); + simple_archiver_helper_32_bit_be(&u32); + CHECK_TRUE(((unsigned char *)&u32)[0] == 4); + CHECK_TRUE(((unsigned char *)&u32)[1] == 3); + CHECK_TRUE(((unsigned char *)&u32)[2] == 2); + CHECK_TRUE(((unsigned char *)&u32)[3] == 1); + + unsigned long long u64 = 0x010203040a0b0c0d; + CHECK_TRUE(((unsigned char *)&u64)[0] == 0xd); + CHECK_TRUE(((unsigned char *)&u64)[1] == 0xc); + CHECK_TRUE(((unsigned char *)&u64)[2] == 0xb); + CHECK_TRUE(((unsigned char *)&u64)[3] == 0xa); + CHECK_TRUE(((unsigned char *)&u64)[4] == 0x4); + CHECK_TRUE(((unsigned char *)&u64)[5] == 0x3); + CHECK_TRUE(((unsigned char *)&u64)[6] == 0x2); + CHECK_TRUE(((unsigned char *)&u64)[7] == 0x1); + simple_archiver_helper_64_bit_be(&u64); + CHECK_TRUE(((unsigned char *)&u64)[0] == 0x1); + CHECK_TRUE(((unsigned char *)&u64)[1] == 0x2); + CHECK_TRUE(((unsigned char *)&u64)[2] == 0x3); + CHECK_TRUE(((unsigned char *)&u64)[3] == 0x4); + CHECK_TRUE(((unsigned char *)&u64)[4] == 0xa); + CHECK_TRUE(((unsigned char *)&u64)[5] == 0xb); + CHECK_TRUE(((unsigned char *)&u64)[6] == 0xc); + CHECK_TRUE(((unsigned char *)&u64)[7] == 0xd); + simple_archiver_helper_64_bit_be(&u64); + CHECK_TRUE(((unsigned char *)&u64)[0] == 0xd); + CHECK_TRUE(((unsigned char *)&u64)[1] == 0xc); + CHECK_TRUE(((unsigned char *)&u64)[2] == 0xb); + CHECK_TRUE(((unsigned char *)&u64)[3] == 0xa); + CHECK_TRUE(((unsigned char *)&u64)[4] == 0x4); + CHECK_TRUE(((unsigned char *)&u64)[5] == 0x3); + CHECK_TRUE(((unsigned char *)&u64)[6] == 0x2); + CHECK_TRUE(((unsigned char *)&u64)[7] == 0x1); + } + } + printf("Checks checked: %u\n", checks_checked); printf("Checks passed: %u\n", checks_passed); return checks_passed == checks_checked ? 0 : 1;