diff --git a/c-programming/fwrite_le.c b/c-programming/fwrite_le.c new file mode 100644 index 0000000..1c56322 --- /dev/null +++ b/c-programming/fwrite_le.c @@ -0,0 +1,91 @@ +#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; +} + +void reorder_le_be( +#if FWRITE_LE_NO_MODIFICATION + uint8_t* dest, uint8_t* src, +#else + uint8_t* bytes, +#endif + size_t count, size_t step) { + for (size_t i = 0; i < count; i += step) { + const size_t div_size = step / 2; + for (size_t j = 0; j < div_size; j++) { + const size_t old_pos = i + j, new_pos = i + step - j - 1; +#if FWRITE_LE_NO_MODIFICATION + dest[old_pos] = src[new_pos]; + dest[new_pos] = src[old_pos]; +#else + uint8_t temp = bytes[old_pos]; + bytes[old_pos] = bytes[new_pos]; + bytes[new_pos] = temp; +#endif + } + } +} + +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); +#endif + + reorder_le_be( +#if FWRITE_LE_NO_MODIFICATION + bytes, +#endif + (uint8_t*) ptr, bytes_count, size); + +#if FWRITE_LE_NO_MODIFICATION + size_t res = +#else + return +#endif + fwrite( +#if FWRITE_LE_NO_MODIFICATION + bytes, +#else + (uint8_t*) ptr, +#endif + size, count, stream); +#if FWRITE_LE_NO_MODIFICATION + free(bytes); + return res; +#endif +} diff --git a/c-programming/fwrite_le.h b/c-programming/fwrite_le.h new file mode 100644 index 0000000..82395e8 --- /dev/null +++ b/c-programming/fwrite_le.h @@ -0,0 +1,25 @@ +#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); +void reorder_le_be( +#if FWRITE_LE_NO_MODIFICATION + uint8_t* dest, uint8_t* src, +#else + uint8_t* bytes, +#endif + size_t count, size_t step); + +#endif /* _FWRITE_LE_H */