/*
 * This file handles input and output with files/memory buffers containing numerical values stored in the little-endian byte order, regardless of the native byte order.
 * This is done using the -DATC_BIG_ENDIAN macro, which should have been set by CMake when on a big-endian machine.
 */

#pragma once

#include <fstream>

// Reads one or more values from a little-endian file stream into a native-byte-order buffer
template<typename Stream, typename T>
void little_endian_file_read(Stream& stream, T* ptr, size_t amount) {
	#ifdef ATC_BIG_ENDIAN
		for (size_t i = 0; i < amount; i++)
			for (size_t byte_pos = sizeof(T); byte_pos-- > 0; )
				stream.read(reinterpret_cast<char*>(&(ptr[i])) + byte_pos, 1);
	#else
		stream.read(reinterpret_cast<char*>(ptr), amount*sizeof(T));
	#endif
}

// Writes one or more values from a native-byte-order buffer into a little-endian file stream
template<typename Stream, typename T>
void little_endian_file_write(Stream& stream, const T* ptr, size_t amount) {
	#ifdef ATC_BIG_ENDIAN
		for (size_t i = 0; i < amount; i++)
			for (size_t byte_pos = sizeof(T); byte_pos-- > 0; )
				stream.write(reinterpret_cast<const char*>(&(ptr[i])) + byte_pos, 1);
	#else
		stream.write(reinterpret_cast<const char*>(ptr), amount*sizeof(T));
	#endif
}

// Reads one or more values from a little-endian byte buffer into a native-byte-order buffer
template<typename T>
void little_endian_memory_read(const char* byte_buffer, size_t offset, T* ptr, size_t amount) {
	#ifdef ATC_BIG_ENDIAN
		for (size_t i = 0; i < amount; i++)
			for (size_t byte_pos = sizeof(T); byte_pos-- > 0; )
				memcpy(reinterpret_cast<char*>(&(ptr[i])) + byte_pos, reinterpret_cast<const char*>(&(byte_buffer[offset + sizeof(T)*i + (sizeof(T) - 1 - byte_pos)])), 1);
	#else
		memcpy(reinterpret_cast<char*>(ptr), reinterpret_cast<const char*>(&(byte_buffer[offset])), amount*sizeof(T));
	#endif
}

// Writes one or more values from a native-byte-order buffer into a little-endian byte buffer
template<typename T>
void little_endian_memory_write(char* byte_buffer, size_t offset, const T* ptr, size_t amount) {
	#ifdef ATC_BIG_ENDIAN
		for (size_t i = 0; i < amount; i++)
			for (size_t byte_pos = sizeof(T); byte_pos-- > 0; )
				memcpy(&(byte_buffer[offset + sizeof(T)*i + (sizeof(T) - 1 - byte_pos)]), reinterpret_cast<const char*>(&(ptr[i])) + byte_pos, 1);
	#else
		memcpy(&(byte_buffer[offset]), reinterpret_cast<const char*>(ptr), amount*sizeof(T));
	#endif
}
