diff --git a/src/fwrite_le.c b/src/fwrite_le.c new file mode 100644 index 0000000..5ab9a1a --- /dev/null +++ b/src/fwrite_le.c @@ -0,0 +1,68 @@ +#include "fwrite_le.h" + +int detect_endianness(void) { + volatile uint32_t i = 0x01234567; + uint8_t* bytes = (uint8_t*)(&i); + if (bytes[0] == 0x01 && + bytes[1] == 0x23 && + bytes[2] == 0x45 && + bytes[3] == 0x67) + return DETECTED_BIG_ENDIAN; + else if ( + bytes[0] == 0x67 && + bytes[1] == 0x45 && + bytes[2] == 0x23 && + bytes[3] == 0x01) + return DETECTED_LITTLE_ENDIAN; + return UNSUPPORTED_ENDIANNESS; +} + +size_t fwrite_le(void* ptr, size_t size, size_t count, FILE* stream) { + /* + * warning: this function modifies `void* ptr` by default! + * (if FWRITE_LE_NO_MODIFICATION in the header is 0) + */ + if (ptr == NULL) + return 0; + + int endianness = detect_endianness(); + if (endianness == UNSUPPORTED_ENDIANNESS) { + fprintf(stderr, "Unsupported endianness\n"); + exit(EXIT_FAILURE); + } else if (endianness == DETECTED_LITTLE_ENDIAN) + return fwrite(ptr, size, count, stream); + + // case: big-endian + size_t bytes_count = size * count; +#if FWRITE_LE_NO_MODIFICATION + uint8_t* bytes = calloc(bytes_count, sizeof(uint8_t)); + if (bytes == NULL) { + perror("calloc"); + exit(EXIT_FAILURE); + } + memcpy(bytes, ptr, bytes_count); +#else + uint8_t* bytes = (uint8_t*) ptr; +#endif + + for (size_t i = 0; i < bytes_count; i += size) { + const size_t div_size = size >> 1; // divide by 2 + for (size_t j = 0; j < div_size; j++) { + const size_t old_pos = i + j, new_pos = i + size - j - 1; + uint8_t temp = bytes[old_pos]; + bytes[old_pos] = bytes[new_pos]; + bytes[new_pos] = temp; + } + } + +#if FWRITE_LE_NO_MODIFICATION + size_t res = +#else + return +#endif + fwrite(bytes, size, count, stream); +#if FWRITE_LE_NO_MODIFICATION + free(bytes); + return res; +#endif +} diff --git a/src/fwrite_le.h b/src/fwrite_le.h new file mode 100644 index 0000000..aa61722 --- /dev/null +++ b/src/fwrite_le.h @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +#ifndef _FWRITE_LE_H +#define _FWRITE_LE_H + +#define FWRITE_LE_NO_MODIFICATION 0 + +#define DETECTED_LITTLE_ENDIAN 0 +#define DETECTED_BIG_ENDIAN 1 +#define UNSUPPORTED_ENDIANNESS -1 + +int detect_endianness(void); +size_t fwrite_le(void* ptr, size_t size, size_t count, FILE* stream); + +#endif /* _FWRITE_LE_H */ diff --git a/src/template.c b/src/template.c index b3e1ea6..aa66b1c 100644 --- a/src/template.c +++ b/src/template.c @@ -7,7 +7,7 @@ #include #include -#include "`path_to_fwrite_le`" +#include "`fwrite_le`" // constants #if defined(_WIN32)