2023-12-31 17:49:42 +05:30
|
|
|
#include "fwrite_le.h"
|
|
|
|
|
2024-07-05 17:51:01 +05:30
|
|
|
#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;
|
|
|
|
|
2023-12-31 17:49:42 +05:30
|
|
|
int detect_endianness(void) {
|
2024-05-19 16:28:26 +05:30
|
|
|
volatile uint32_t native_order_value = ORDER_NATIVE_U32;
|
|
|
|
uint8_t* as_bytes = (uint8_t*)&native_order_value;
|
|
|
|
|
2024-06-01 12:31:38 +05:30
|
|
|
ifeq_b32_ret(as_bytes, ORDER_LITTLE_ENDIAN_S4, DETECTED_LITTLE_ENDIAN);
|
|
|
|
ifeq_b32_ret(as_bytes, ORDER_BIG_ENDIAN_S4, DETECTED_BIG_ENDIAN );
|
2023-12-31 17:49:42 +05:30
|
|
|
return UNSUPPORTED_ENDIANNESS;
|
|
|
|
}
|
|
|
|
|
2024-01-24 22:29:05 +05:30
|
|
|
void reorder_le_be(
|
2024-01-02 02:49:51 +05:30
|
|
|
#if FWRITE_LE_NO_MODIFICATION
|
|
|
|
uint8_t* dest, uint8_t* src,
|
|
|
|
#else
|
|
|
|
uint8_t* bytes,
|
|
|
|
#endif
|
|
|
|
size_t count, size_t step) {
|
2024-05-19 16:53:50 +05:30
|
|
|
|
|
|
|
if (step == 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-02 02:49:51 +05:30
|
|
|
for (size_t i = 0; i < count; i += step) {
|
2024-01-21 15:59:34 +05:30
|
|
|
const size_t div_size = step / 2;
|
2024-01-02 02:49:51 +05:30
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-18 20:45:32 +05:30
|
|
|
size_t fwrite_le(
|
|
|
|
#if FWRITE_LE_NO_MODIFICATION
|
|
|
|
const
|
|
|
|
#endif
|
|
|
|
void* ptr, size_t size, size_t count, FILE* stream) {
|
2023-12-31 17:49:42 +05:30
|
|
|
/*
|
|
|
|
* 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();
|
2024-05-19 16:53:50 +05:30
|
|
|
if (size == 1 || endianness == DETECTED_LITTLE_ENDIAN)
|
|
|
|
return fwrite(ptr, size, count, stream);
|
|
|
|
else if (endianness == UNSUPPORTED_ENDIANNESS) {
|
2023-12-31 17:49:42 +05:30
|
|
|
fprintf(stderr, "Unsupported endianness\n");
|
|
|
|
exit(EXIT_FAILURE);
|
2024-05-19 16:53:50 +05:30
|
|
|
}
|
2023-12-31 17:49:42 +05:30
|
|
|
|
|
|
|
// 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
|
|
|
|
|
2024-01-24 22:29:05 +05:30
|
|
|
reorder_le_be(
|
2023-12-31 18:08:28 +05:30
|
|
|
#if FWRITE_LE_NO_MODIFICATION
|
2024-01-02 02:49:51 +05:30
|
|
|
bytes,
|
2023-12-31 18:08:28 +05:30
|
|
|
#endif
|
2024-01-02 02:49:51 +05:30
|
|
|
(uint8_t*) ptr, bytes_count, size);
|
2023-12-31 17:49:42 +05:30
|
|
|
|
|
|
|
#if FWRITE_LE_NO_MODIFICATION
|
|
|
|
size_t res =
|
|
|
|
#else
|
|
|
|
return
|
|
|
|
#endif
|
2024-01-02 02:49:51 +05:30
|
|
|
fwrite(
|
|
|
|
#if FWRITE_LE_NO_MODIFICATION
|
|
|
|
bytes,
|
|
|
|
#else
|
|
|
|
(uint8_t*) ptr,
|
|
|
|
#endif
|
|
|
|
size, count, stream);
|
2023-12-31 17:49:42 +05:30
|
|
|
#if FWRITE_LE_NO_MODIFICATION
|
|
|
|
free(bytes);
|
|
|
|
return res;
|
|
|
|
#endif
|
|
|
|
}
|