#include "fwrite_le.h" #define ORDER_NATIVE_U32 0x01234567 #define ORDER_LITTLE_ENDIAN_S4 "\x67\x45\x23\x01" #define ORDER_BIG_ENDIAN_S4 "\x01\x23\x45\x67" #define ifeq_b32_ret(lhs, rhs, value) if (!memcmp(lhs, rhs, 4)) return value; int detect_endianness(void) { volatile uint32_t native_order_value = ORDER_NATIVE_U32; uint8_t* as_bytes = (uint8_t*)&native_order_value; ifeq_b32_ret(as_bytes, ORDER_LITTLE_ENDIAN_S4, DETECTED_LITTLE_ENDIAN); ifeq_b32_ret(as_bytes, ORDER_BIG_ENDIAN_S4, DETECTED_BIG_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) { if (step == 1) { return; } 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( #if FWRITE_LE_NO_MODIFICATION const #endif 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 (size == 1 || endianness == DETECTED_LITTLE_ENDIAN) return fwrite(ptr, size, count, stream); else if (endianness == UNSUPPORTED_ENDIANNESS) { fprintf(stderr, "Unsupported endianness\n"); exit(EXIT_FAILURE); } // 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 }