Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
122
Src/external_dependencies/openmpt-trunk/src/mpt/io/base.hpp
Normal file
122
Src/external_dependencies/openmpt-trunk/src/mpt/io/base.hpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
|
||||
|
||||
#ifndef MPT_IO_BASE_HPP
|
||||
#define MPT_IO_BASE_HPP
|
||||
|
||||
|
||||
|
||||
#include "mpt/base/integer.hpp"
|
||||
#include "mpt/base/namespace.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
inline namespace MPT_INLINE_NS {
|
||||
|
||||
|
||||
|
||||
namespace IO {
|
||||
|
||||
|
||||
|
||||
using Offset = int64;
|
||||
|
||||
inline constexpr std::size_t BUFFERSIZE_MINUSCULE = 1 * 256; // on stack usage, tuned for single word/line buffers
|
||||
inline constexpr std::size_t BUFFERSIZE_TINY = 1 * 1024; // on stack usage
|
||||
inline constexpr std::size_t BUFFERSIZE_SMALL = 4 * 1024; // on heap
|
||||
inline constexpr std::size_t BUFFERSIZE_NORMAL = 64 * 1024; // FILE I/O
|
||||
inline constexpr std::size_t BUFFERSIZE_LARGE = 1024 * 1024;
|
||||
|
||||
|
||||
|
||||
template <typename Tfile, typename Enable = void>
|
||||
struct FileOperations {
|
||||
};
|
||||
|
||||
template <typename Tfile>
|
||||
inline FileOperations<Tfile> FileOps(Tfile & f) {
|
||||
;
|
||||
return FileOperations<Tfile>{f};
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool IsValid(Tfile & f) {
|
||||
return FileOps(f).IsValid();
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool IsReadSeekable(Tfile & f) {
|
||||
return FileOps(f).IsReadSeekable();
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool IsWriteSeekable(Tfile & f) {
|
||||
return FileOps(f).IsWriteSeekable();
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline IO::Offset TellRead(Tfile & f) {
|
||||
return FileOps(f).TellRead();
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline IO::Offset TellWrite(Tfile & f) {
|
||||
return FileOps(f).TellWrite();
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool SeekBegin(Tfile & f) {
|
||||
return FileOps(f).SeekBegin();
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool SeekEnd(Tfile & f) {
|
||||
return FileOps(f).SeekEnd();
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool SeekAbsolute(Tfile & f, IO::Offset pos) {
|
||||
return FileOps(f).SeekAbsolute(pos);
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool SeekRelative(Tfile & f, IO::Offset off) {
|
||||
return FileOps(f).SeekRelative(off);
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline mpt::byte_span ReadRawImpl(Tfile & f, mpt::byte_span data) {
|
||||
return FileOps(f).ReadRawImpl(data);
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteRawImpl(Tfile & f, mpt::const_byte_span data) {
|
||||
return FileOps(f).WriteRawImpl(data);
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool IsEof(Tfile & f) {
|
||||
return FileOps(f).IsEof();
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool Flush(Tfile & f) {
|
||||
return FileOps(f).Flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
|
||||
|
||||
} // namespace MPT_INLINE_NS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#endif // MPT_IO_BASE_HPP
|
367
Src/external_dependencies/openmpt-trunk/src/mpt/io/io.hpp
Normal file
367
Src/external_dependencies/openmpt-trunk/src/mpt/io/io.hpp
Normal file
|
@ -0,0 +1,367 @@
|
|||
/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
|
||||
|
||||
#ifndef MPT_IO_IO_HPP
|
||||
#define MPT_IO_IO_HPP
|
||||
|
||||
|
||||
|
||||
#include "mpt/base/array.hpp"
|
||||
#include "mpt/base/bit.hpp"
|
||||
#include "mpt/base/integer.hpp"
|
||||
#include "mpt/base/memory.hpp"
|
||||
#include "mpt/base/namespace.hpp"
|
||||
#include "mpt/base/span.hpp"
|
||||
#include "mpt/endian/integer.hpp"
|
||||
#include "mpt/io/base.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
inline namespace MPT_INLINE_NS {
|
||||
|
||||
|
||||
|
||||
namespace IO {
|
||||
|
||||
|
||||
|
||||
template <typename Tbyte, typename Tfile>
|
||||
inline mpt::byte_span ReadRaw(Tfile & f, Tbyte * data, std::size_t size) {
|
||||
return mpt::IO::ReadRawImpl(f, mpt::as_span(mpt::byte_cast<std::byte *>(data), size));
|
||||
}
|
||||
|
||||
template <typename Tbyte, typename Tfile>
|
||||
inline mpt::byte_span ReadRaw(Tfile & f, mpt::span<Tbyte> data) {
|
||||
return mpt::IO::ReadRawImpl(f, mpt::byte_cast<mpt::byte_span>(data));
|
||||
}
|
||||
|
||||
template <typename Tbyte, typename Tfile>
|
||||
inline bool WriteRaw(Tfile & f, const Tbyte * data, std::size_t size) {
|
||||
return mpt::IO::WriteRawImpl(f, mpt::as_span(mpt::byte_cast<const std::byte *>(data), size));
|
||||
}
|
||||
|
||||
template <typename Tbyte, typename Tfile>
|
||||
inline bool WriteRaw(Tfile & f, mpt::span<Tbyte> data) {
|
||||
return mpt::IO::WriteRawImpl(f, mpt::byte_cast<mpt::const_byte_span>(data));
|
||||
}
|
||||
|
||||
template <typename Tbinary, typename Tfile>
|
||||
inline bool Read(Tfile & f, Tbinary & v) {
|
||||
return mpt::IO::ReadRaw(f, mpt::as_raw_memory(v)).size() == mpt::as_raw_memory(v).size();
|
||||
}
|
||||
|
||||
template <typename Tbinary, typename Tfile>
|
||||
inline bool Write(Tfile & f, const Tbinary & v) {
|
||||
return mpt::IO::WriteRaw(f, mpt::as_raw_memory(v));
|
||||
}
|
||||
|
||||
template <typename Tbinary, typename Tfile>
|
||||
inline bool Write(Tfile & f, const std::vector<Tbinary> & v) {
|
||||
static_assert(mpt::is_binary_safe<Tbinary>::value);
|
||||
return mpt::IO::WriteRaw(f, mpt::as_raw_memory(v));
|
||||
}
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
inline bool WritePartial(Tfile & f, const T & v, std::size_t size = sizeof(T)) {
|
||||
assert(size <= sizeof(T));
|
||||
return mpt::IO::WriteRaw(f, mpt::as_span(mpt::as_raw_memory(v).data(), size));
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool ReadByte(Tfile & f, std::byte & v) {
|
||||
bool result = false;
|
||||
std::byte byte = mpt::as_byte(0);
|
||||
const std::size_t readResult = mpt::IO::ReadRaw(f, &byte, sizeof(std::byte)).size();
|
||||
result = (readResult == sizeof(std::byte));
|
||||
v = byte;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
inline bool ReadBinaryTruncatedLE(Tfile & f, T & v, std::size_t size) {
|
||||
bool result = false;
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
std::array<uint8, sizeof(T)> bytes = mpt::init_array<uint8, sizeof(T)>(uint8{0});
|
||||
const std::size_t readResult = mpt::IO::ReadRaw(f, bytes.data(), std::min(size, sizeof(T))).size();
|
||||
result = (readResult == std::min(size, sizeof(T)));
|
||||
v = mpt::bit_cast<typename mpt::make_le<T>::type>(bytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
inline bool ReadIntLE(Tfile & f, T & v) {
|
||||
bool result = false;
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
std::array<uint8, sizeof(T)> bytes = mpt::init_array<uint8, sizeof(T)>(uint8{0});
|
||||
const std::size_t readResult = mpt::IO::ReadRaw(f, mpt::as_span(bytes)).size();
|
||||
result = (readResult == sizeof(T));
|
||||
v = mpt::bit_cast<typename mpt::make_le<T>::type>(bytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
inline bool ReadIntBE(Tfile & f, T & v) {
|
||||
bool result = false;
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
std::array<uint8, sizeof(T)> bytes = mpt::init_array<uint8, sizeof(T)>(uint8{0});
|
||||
const std::size_t readResult = mpt::IO::ReadRaw(f, mpt::as_span(bytes)).size();
|
||||
result = (readResult == sizeof(T));
|
||||
v = mpt::bit_cast<typename mpt::make_be<T>::type>(bytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool ReadAdaptiveInt16LE(Tfile & f, uint16 & v) {
|
||||
bool result = true;
|
||||
uint8 byte = 0;
|
||||
std::size_t additionalBytes = 0;
|
||||
v = 0;
|
||||
byte = 0;
|
||||
if (!mpt::IO::ReadIntLE<uint8>(f, byte)) {
|
||||
result = false;
|
||||
}
|
||||
additionalBytes = (byte & 0x01);
|
||||
v = byte >> 1;
|
||||
for (std::size_t i = 0; i < additionalBytes; ++i) {
|
||||
byte = 0;
|
||||
if (!mpt::IO::ReadIntLE<uint8>(f, byte)) {
|
||||
result = false;
|
||||
}
|
||||
v |= (static_cast<uint16>(byte) << (((i + 1) * 8) - 1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool ReadAdaptiveInt32LE(Tfile & f, uint32 & v) {
|
||||
bool result = true;
|
||||
uint8 byte = 0;
|
||||
std::size_t additionalBytes = 0;
|
||||
v = 0;
|
||||
byte = 0;
|
||||
if (!mpt::IO::ReadIntLE<uint8>(f, byte)) {
|
||||
result = false;
|
||||
}
|
||||
additionalBytes = (byte & 0x03);
|
||||
v = byte >> 2;
|
||||
for (std::size_t i = 0; i < additionalBytes; ++i) {
|
||||
byte = 0;
|
||||
if (!mpt::IO::ReadIntLE<uint8>(f, byte)) {
|
||||
result = false;
|
||||
}
|
||||
v |= (static_cast<uint32>(byte) << (((i + 1) * 8) - 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool ReadAdaptiveInt64LE(Tfile & f, uint64 & v) {
|
||||
bool result = true;
|
||||
uint8 byte = 0;
|
||||
std::size_t additionalBytes = 0;
|
||||
v = 0;
|
||||
byte = 0;
|
||||
if (!mpt::IO::ReadIntLE<uint8>(f, byte)) {
|
||||
result = false;
|
||||
}
|
||||
additionalBytes = (1 << (byte & 0x03)) - 1;
|
||||
v = byte >> 2;
|
||||
for (std::size_t i = 0; i < additionalBytes; ++i) {
|
||||
byte = 0;
|
||||
if (!mpt::IO::ReadIntLE<uint8>(f, byte)) {
|
||||
result = false;
|
||||
}
|
||||
v |= (static_cast<uint64>(byte) << (((i + 1) * 8) - 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Tsize, typename Tfile>
|
||||
inline bool ReadSizedStringLE(Tfile & f, std::string & str, Tsize maxSize = std::numeric_limits<Tsize>::max()) {
|
||||
static_assert(std::numeric_limits<Tsize>::is_integer);
|
||||
str.clear();
|
||||
Tsize size = 0;
|
||||
if (!mpt::IO::ReadIntLE(f, size)) {
|
||||
return false;
|
||||
}
|
||||
if (size > maxSize) {
|
||||
return false;
|
||||
}
|
||||
for (Tsize i = 0; i != size; ++i) {
|
||||
char c = '\0';
|
||||
if (!mpt::IO::ReadIntLE(f, c)) {
|
||||
return false;
|
||||
}
|
||||
str.push_back(c);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
inline bool WriteIntLE(Tfile & f, const T v) {
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
return mpt::IO::Write(f, mpt::as_le(v));
|
||||
}
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
inline bool WriteIntBE(Tfile & f, const T v) {
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
return mpt::IO::Write(f, mpt::as_be(v));
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteAdaptiveInt16LE(Tfile & f, const uint16 v, std::size_t fixedSize = 0) {
|
||||
std::size_t minSize = fixedSize;
|
||||
std::size_t maxSize = fixedSize;
|
||||
assert(minSize == 0 || minSize == 1 || minSize == 2);
|
||||
assert(maxSize == 0 || maxSize == 1 || maxSize == 2);
|
||||
assert(maxSize == 0 || maxSize >= minSize);
|
||||
if (maxSize == 0) {
|
||||
maxSize = 2;
|
||||
}
|
||||
if (v < 0x80 && minSize <= 1 && 1 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint8>(f, static_cast<uint8>(v << 1) | 0x00);
|
||||
} else if (v < 0x8000 && minSize <= 2 && 2 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint16>(f, static_cast<uint16>(v << 1) | 0x01);
|
||||
} else {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteAdaptiveInt32LE(Tfile & f, const uint32 v, std::size_t fixedSize = 0) {
|
||||
std::size_t minSize = fixedSize;
|
||||
std::size_t maxSize = fixedSize;
|
||||
assert(minSize == 0 || minSize == 1 || minSize == 2 || minSize == 3 || minSize == 4);
|
||||
assert(maxSize == 0 || maxSize == 1 || maxSize == 2 || maxSize == 3 || maxSize == 4);
|
||||
assert(maxSize == 0 || maxSize >= minSize);
|
||||
if (maxSize == 0) {
|
||||
maxSize = 4;
|
||||
}
|
||||
if (v < 0x40 && minSize <= 1 && 1 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint8>(f, static_cast<uint8>(v << 2) | 0x00);
|
||||
} else if (v < 0x4000 && minSize <= 2 && 2 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint16>(f, static_cast<uint16>(v << 2) | 0x01);
|
||||
} else if (v < 0x400000 && minSize <= 3 && 3 <= maxSize) {
|
||||
uint32 value = static_cast<uint32>(v << 2) | 0x02;
|
||||
std::byte bytes[3];
|
||||
bytes[0] = static_cast<std::byte>(value >> 0);
|
||||
bytes[1] = static_cast<std::byte>(value >> 8);
|
||||
bytes[2] = static_cast<std::byte>(value >> 16);
|
||||
return mpt::IO::WriteRaw(f, bytes, 3);
|
||||
} else if (v < 0x40000000 && minSize <= 4 && 4 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint32>(f, static_cast<uint32>(v << 2) | 0x03);
|
||||
} else {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteAdaptiveInt64LE(Tfile & f, const uint64 v, std::size_t fixedSize = 0) {
|
||||
std::size_t minSize = fixedSize;
|
||||
std::size_t maxSize = fixedSize;
|
||||
assert(minSize == 0 || minSize == 1 || minSize == 2 || minSize == 4 || minSize == 8);
|
||||
assert(maxSize == 0 || maxSize == 1 || maxSize == 2 || maxSize == 4 || maxSize == 8);
|
||||
assert(maxSize == 0 || maxSize >= minSize);
|
||||
if (maxSize == 0) {
|
||||
maxSize = 8;
|
||||
}
|
||||
if (v < 0x40 && minSize <= 1 && 1 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint8>(f, static_cast<uint8>(v << 2) | 0x00);
|
||||
} else if (v < 0x4000 && minSize <= 2 && 2 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint16>(f, static_cast<uint16>(v << 2) | 0x01);
|
||||
} else if (v < 0x40000000 && minSize <= 4 && 4 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint32>(f, static_cast<uint32>(v << 2) | 0x02);
|
||||
} else if (v < 0x4000000000000000ull && minSize <= 8 && 8 <= maxSize) {
|
||||
return mpt::IO::WriteIntLE<uint64>(f, static_cast<uint64>(v << 2) | 0x03);
|
||||
} else {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Write a variable-length integer, as found in MIDI files. The number of written bytes is placed in the bytesWritten parameter.
|
||||
template <typename Tfile, typename T>
|
||||
bool WriteVarInt(Tfile & f, const T v, std::size_t * bytesWritten = nullptr) {
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
static_assert(!std::numeric_limits<T>::is_signed);
|
||||
std::byte out[(sizeof(T) * 8 + 6) / 7];
|
||||
std::size_t numBytes = 0;
|
||||
for (uint32 n = (sizeof(T) * 8) / 7; n > 0; n--) {
|
||||
if (v >= (static_cast<T>(1) << (n * 7u))) {
|
||||
out[numBytes++] = static_cast<std::byte>(((v >> (n * 7u)) & 0x7F) | 0x80);
|
||||
}
|
||||
}
|
||||
out[numBytes++] = static_cast<std::byte>(v & 0x7F);
|
||||
assert(numBytes <= std::size(out));
|
||||
if (bytesWritten != nullptr) {
|
||||
*bytesWritten = numBytes;
|
||||
}
|
||||
return mpt::IO::WriteRaw(f, out, numBytes);
|
||||
}
|
||||
|
||||
template <typename Tsize, typename Tfile>
|
||||
inline bool WriteSizedStringLE(Tfile & f, const std::string & str) {
|
||||
static_assert(std::numeric_limits<Tsize>::is_integer);
|
||||
if (str.size() > std::numeric_limits<Tsize>::max()) {
|
||||
return false;
|
||||
}
|
||||
Tsize size = static_cast<Tsize>(str.size());
|
||||
if (!mpt::IO::WriteIntLE(f, size)) {
|
||||
return false;
|
||||
}
|
||||
if (!mpt::IO::WriteRaw(f, str.data(), str.size())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteText(Tfile & f, const std::string & s) {
|
||||
return mpt::IO::WriteRaw(f, s.data(), s.size());
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteTextCRLF(Tfile & f) {
|
||||
return mpt::IO::WriteText(f, "\r\n");
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteTextLF(Tfile & f) {
|
||||
return mpt::IO::WriteText(f, "\n");
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteTextCRLF(Tfile & f, const std::string & s) {
|
||||
return mpt::IO::WriteText(f, s) && mpt::IO::WriteTextCRLF(f);
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteTextLF(Tfile & f, const std::string & s) {
|
||||
return mpt::IO::WriteText(f, s) && mpt::IO::WriteTextLF(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
|
||||
|
||||
} // namespace MPT_INLINE_NS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#endif // MPT_IO_IO_HPP
|
146
Src/external_dependencies/openmpt-trunk/src/mpt/io/io_span.hpp
Normal file
146
Src/external_dependencies/openmpt-trunk/src/mpt/io/io_span.hpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
|
||||
|
||||
#ifndef MPT_IO_IO_SPAN_HPP
|
||||
#define MPT_IO_IO_SPAN_HPP
|
||||
|
||||
|
||||
|
||||
#include "mpt/base/macros.hpp"
|
||||
#include "mpt/base/memory.hpp"
|
||||
#include "mpt/base/namespace.hpp"
|
||||
#include "mpt/base/saturate_cast.hpp"
|
||||
#include "mpt/base/span.hpp"
|
||||
#include "mpt/io/base.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
inline namespace MPT_INLINE_NS {
|
||||
|
||||
|
||||
|
||||
namespace IO {
|
||||
|
||||
|
||||
|
||||
template <typename Tbyte>
|
||||
struct FileOperations<std::pair<mpt::span<Tbyte>, IO::Offset>> {
|
||||
|
||||
private:
|
||||
std::pair<mpt::span<Tbyte>, IO::Offset> & f;
|
||||
|
||||
public:
|
||||
FileOperations(std::pair<mpt::span<Tbyte>, IO::Offset> & f_)
|
||||
: f(f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool IsValid() {
|
||||
return (f.second >= 0);
|
||||
}
|
||||
|
||||
inline bool IsReadSeekable() {
|
||||
MPT_UNUSED(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsWriteSeekable() {
|
||||
MPT_UNUSED(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline IO::Offset TellRead() {
|
||||
return f.second;
|
||||
}
|
||||
|
||||
inline IO::Offset TellWrite() {
|
||||
return f.second;
|
||||
}
|
||||
|
||||
inline bool SeekBegin() {
|
||||
f.second = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SeekEnd() {
|
||||
f.second = f.first.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SeekAbsolute(IO::Offset pos) {
|
||||
f.second = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SeekRelative(IO::Offset off) {
|
||||
if (f.second < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
f.second += off;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline mpt::byte_span ReadRawImpl(mpt::byte_span data) {
|
||||
if (f.second < 0)
|
||||
{
|
||||
return data.first(0);
|
||||
}
|
||||
if (f.second >= static_cast<IO::Offset>(f.first.size()))
|
||||
{
|
||||
return data.first(0);
|
||||
}
|
||||
std::size_t num = mpt::saturate_cast<std::size_t>(std::min(static_cast<IO::Offset>(f.first.size()) - f.second, static_cast<IO::Offset>(data.size())));
|
||||
std::copy(mpt::byte_cast<const std::byte *>(f.first.data() + f.second), mpt::byte_cast<const std::byte *>(f.first.data() + f.second + num), data.data());
|
||||
f.second += num;
|
||||
return data.first(num);
|
||||
}
|
||||
|
||||
inline bool WriteRawImpl(mpt::const_byte_span data) {
|
||||
if (f.second < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (f.second > static_cast<IO::Offset>(f.first.size()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::size_t num = mpt::saturate_cast<std::size_t>(std::min(static_cast<IO::Offset>(f.first.size()) - f.second, static_cast<IO::Offset>(data.size())));
|
||||
if (num != data.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::copy(data.data(), data.data() + num, mpt::byte_cast<std::byte *>(f.first.data() + f.second));
|
||||
f.second += num;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsEof() {
|
||||
return (f.second >= static_cast<IO::Offset>(f.first.size()));
|
||||
}
|
||||
|
||||
inline bool Flush() {
|
||||
MPT_UNUSED(f);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
|
||||
|
||||
} // namespace MPT_INLINE_NS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#endif // MPT_IO_IO_SPAN_HPP
|
|
@ -0,0 +1,332 @@
|
|||
/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
|
||||
|
||||
#ifndef MPT_IO_IO_STDSTREAM_HPP
|
||||
#define MPT_IO_IO_STDSTREAM_HPP
|
||||
|
||||
|
||||
|
||||
#include "mpt/base/macros.hpp"
|
||||
#include "mpt/base/memory.hpp"
|
||||
#include "mpt/base/namespace.hpp"
|
||||
#include "mpt/base/utility.hpp"
|
||||
#include "mpt/io/base.hpp"
|
||||
|
||||
#include <ios>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
inline namespace MPT_INLINE_NS {
|
||||
|
||||
|
||||
|
||||
namespace IO {
|
||||
|
||||
|
||||
|
||||
//static_assert(sizeof(std::streamoff) == 8); // Assert 64bit file support.
|
||||
|
||||
struct FileOperationsStdIos {
|
||||
|
||||
private:
|
||||
std::ios & f;
|
||||
|
||||
public:
|
||||
FileOperationsStdIos(std::ios & f_)
|
||||
: f(f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool IsValid() {
|
||||
return !f.fail();
|
||||
}
|
||||
};
|
||||
|
||||
struct FileOperationsStdIstream
|
||||
: public FileOperationsStdIos {
|
||||
|
||||
private:
|
||||
std::istream & f;
|
||||
|
||||
public:
|
||||
FileOperationsStdIstream(std::istream & f_)
|
||||
: FileOperationsStdIos(f_)
|
||||
, f(f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool IsReadSeekable() {
|
||||
f.clear();
|
||||
std::streampos oldpos = f.tellg();
|
||||
if (f.fail() || oldpos == std::streampos(-1))
|
||||
{
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekg(0, std::ios::beg);
|
||||
if (f.fail())
|
||||
{
|
||||
f.clear();
|
||||
f.seekg(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekg(0, std::ios::end);
|
||||
if (f.fail())
|
||||
{
|
||||
f.clear();
|
||||
f.seekg(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
std::streampos length = f.tellg();
|
||||
if (f.fail() || length == std::streampos(-1))
|
||||
{
|
||||
f.clear();
|
||||
f.seekg(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekg(oldpos);
|
||||
f.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline IO::Offset TellRead() {
|
||||
return f.tellg();
|
||||
}
|
||||
|
||||
inline bool SeekBegin() {
|
||||
f.seekg(0);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekEnd() {
|
||||
f.seekg(0, std::ios::end);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekAbsolute(IO::Offset pos) {
|
||||
if (!mpt::in_range<std::streamoff>(pos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
f.seekg(static_cast<std::streamoff>(pos), std::ios::beg);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekRelative(IO::Offset off) {
|
||||
if (!mpt::in_range<std::streamoff>(off))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
f.seekg(static_cast<std::streamoff>(off), std::ios::cur);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline mpt::byte_span ReadRawImpl(mpt::byte_span data) {
|
||||
f.read(mpt::byte_cast<char *>(data.data()), data.size());
|
||||
return data.first(mpt::saturate_cast<std::size_t>(f.gcount()));
|
||||
}
|
||||
|
||||
inline bool IsEof() {
|
||||
return f.eof();
|
||||
}
|
||||
};
|
||||
|
||||
struct FileOperationsStdOstream
|
||||
: public FileOperationsStdIos {
|
||||
|
||||
private:
|
||||
std::ostream & f;
|
||||
|
||||
public:
|
||||
FileOperationsStdOstream(std::ostream & f_)
|
||||
: FileOperationsStdIos(f_)
|
||||
, f(f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool IsWriteSeekable() {
|
||||
f.clear();
|
||||
std::streampos oldpos = f.tellp();
|
||||
if (f.fail() || oldpos == std::streampos(-1))
|
||||
{
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekp(0, std::ios::beg);
|
||||
if (f.fail())
|
||||
{
|
||||
f.clear();
|
||||
f.seekp(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekp(0, std::ios::end);
|
||||
if (f.fail())
|
||||
{
|
||||
f.clear();
|
||||
f.seekp(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
std::streampos length = f.tellp();
|
||||
if (f.fail() || length == std::streampos(-1))
|
||||
{
|
||||
f.clear();
|
||||
f.seekp(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekp(oldpos);
|
||||
f.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline IO::Offset TellWrite() {
|
||||
return f.tellp();
|
||||
}
|
||||
|
||||
inline bool SeekBegin() {
|
||||
f.seekp(0);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekEnd() {
|
||||
f.seekp(0, std::ios::end);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekAbsolute(IO::Offset pos) {
|
||||
if (!mpt::in_range<std::streamoff>(pos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
f.seekp(static_cast<std::streamoff>(pos), std::ios::beg);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekRelative(IO::Offset off) {
|
||||
if (!mpt::in_range<std::streamoff>(off))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
f.seekp(static_cast<std::streamoff>(off), std::ios::cur);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool WriteRawImpl(mpt::const_byte_span data) {
|
||||
f.write(mpt::byte_cast<const char *>(data.data()), data.size());
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool Flush() {
|
||||
f.flush();
|
||||
return !f.fail();
|
||||
}
|
||||
};
|
||||
|
||||
struct FileOperationsStdIOstream
|
||||
: public FileOperationsStdIstream
|
||||
, public FileOperationsStdOstream {
|
||||
|
||||
private:
|
||||
std::iostream & f;
|
||||
|
||||
public:
|
||||
FileOperationsStdIOstream(std::iostream & f_)
|
||||
: FileOperationsStdIstream(f_)
|
||||
, FileOperationsStdOstream(f_)
|
||||
, f(f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool SeekBegin() {
|
||||
FileOperationsStdIstream::SeekBegin();
|
||||
FileOperationsStdOstream::SeekBegin();
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekEnd() {
|
||||
FileOperationsStdIstream::SeekEnd();
|
||||
FileOperationsStdOstream::SeekEnd();
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekAbsolute(IO::Offset pos) {
|
||||
if (!mpt::in_range<std::streamoff>(pos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
FileOperationsStdIstream::SeekAbsolute(pos);
|
||||
FileOperationsStdOstream::SeekAbsolute(pos);
|
||||
return !f.fail();
|
||||
}
|
||||
|
||||
inline bool SeekRelative(IO::Offset off) {
|
||||
if (!mpt::in_range<std::streamoff>(off))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
FileOperationsStdIstream::SeekRelative(off);
|
||||
FileOperationsStdOstream::SeekRelative(off);
|
||||
return !f.fail();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Tstream>
|
||||
struct FileOperations<Tstream, typename std::enable_if_t<std::is_base_of<std::iostream, Tstream>::value>>
|
||||
: public FileOperationsStdIOstream {
|
||||
public:
|
||||
FileOperations(Tstream & f)
|
||||
: FileOperationsStdIOstream(f) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Tstream>
|
||||
struct FileOperations<Tstream, typename std::enable_if_t<std::is_base_of<std::istream, Tstream>::value && !std::is_base_of<std::iostream, Tstream>::value>>
|
||||
: public FileOperationsStdIstream {
|
||||
public:
|
||||
FileOperations(Tstream & f)
|
||||
: FileOperationsStdIstream(f) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Tstream>
|
||||
struct FileOperations<Tstream, typename std::enable_if_t<std::is_base_of<std::ostream, Tstream>::value && !std::is_base_of<std::iostream, Tstream>::value>>
|
||||
: public FileOperationsStdOstream {
|
||||
public:
|
||||
FileOperations(Tstream & f)
|
||||
: FileOperationsStdOstream(f) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
|
||||
|
||||
} // namespace MPT_INLINE_NS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#endif // MPT_IO_IO_STDSTREAM_HPP
|
|
@ -0,0 +1,405 @@
|
|||
/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
|
||||
|
||||
#ifndef MPT_IO_IO_VIRTUAL_WRAPPER_HPP
|
||||
#define MPT_IO_IO_VIRTUAL_WRAPPER_HPP
|
||||
|
||||
|
||||
|
||||
#include "mpt/base/memory.hpp"
|
||||
#include "mpt/base/namespace.hpp"
|
||||
#include "mpt/io/base.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
inline namespace MPT_INLINE_NS {
|
||||
|
||||
|
||||
|
||||
namespace IO {
|
||||
|
||||
|
||||
|
||||
class IFileBase {
|
||||
protected:
|
||||
IFileBase() = default;
|
||||
virtual ~IFileBase() = default;
|
||||
|
||||
public:
|
||||
virtual bool IsValid() = 0;
|
||||
virtual bool IsReadSeekable() = 0;
|
||||
virtual IO::Offset TellRead() = 0;
|
||||
virtual bool SeekBegin() = 0;
|
||||
virtual bool SeekEnd() = 0;
|
||||
virtual bool SeekAbsolute(IO::Offset pos) = 0;
|
||||
virtual bool SeekRelative(IO::Offset off) = 0;
|
||||
virtual mpt::byte_span ReadRawImpl(mpt::byte_span data) = 0;
|
||||
virtual bool IsEof() = 0;
|
||||
};
|
||||
|
||||
template <typename Tfile>
|
||||
class IFile
|
||||
: public IFileBase {
|
||||
private:
|
||||
Tfile & f;
|
||||
|
||||
public:
|
||||
IFile(Tfile & f_)
|
||||
: f(f_) {
|
||||
}
|
||||
~IFile() override = default;
|
||||
|
||||
public:
|
||||
bool IsValid() override {
|
||||
return mpt::IO::IsValid(f);
|
||||
}
|
||||
bool IsReadSeekable() override {
|
||||
return mpt::IO::IsReadSeekable(f);
|
||||
}
|
||||
IO::Offset TellRead() override {
|
||||
return mpt::IO::TellRead(f);
|
||||
}
|
||||
bool SeekBegin() override {
|
||||
return mpt::IO::SeekBegin(f);
|
||||
}
|
||||
bool SeekEnd() override {
|
||||
return mpt::IO::SeekEnd(f);
|
||||
}
|
||||
bool SeekAbsolute(IO::Offset pos) override {
|
||||
return mpt::IO::SeekAbsolute(f, pos);
|
||||
}
|
||||
bool SeekRelative(IO::Offset off) override {
|
||||
return mpt::IO::SeekRelative(f, off);
|
||||
}
|
||||
mpt::byte_span ReadRawImpl(mpt::byte_span data) override {
|
||||
return mpt::IO::ReadRawImpl(f, data);
|
||||
}
|
||||
bool IsEof() override {
|
||||
return mpt::IO::IsEof(f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class OFileBase {
|
||||
protected:
|
||||
OFileBase() = default;
|
||||
virtual ~OFileBase() = default;
|
||||
|
||||
public:
|
||||
virtual bool IsValid() = 0;
|
||||
virtual bool IsWriteSeekable() = 0;
|
||||
virtual IO::Offset TellWrite() = 0;
|
||||
virtual bool SeekBegin() = 0;
|
||||
virtual bool SeekEnd() = 0;
|
||||
virtual bool SeekAbsolute(IO::Offset pos) = 0;
|
||||
virtual bool SeekRelative(IO::Offset off) = 0;
|
||||
virtual bool WriteRawImpl(mpt::const_byte_span data) = 0;
|
||||
virtual bool Flush() = 0;
|
||||
};
|
||||
|
||||
template <typename Tfile>
|
||||
class OFile
|
||||
: public OFileBase {
|
||||
private:
|
||||
Tfile & f;
|
||||
|
||||
public:
|
||||
OFile(Tfile & f_)
|
||||
: f(f_) {
|
||||
}
|
||||
~OFile() override = default;
|
||||
|
||||
public:
|
||||
bool IsValid() override {
|
||||
return mpt::IO::IsValid(f);
|
||||
}
|
||||
bool IsWriteSeekable() override {
|
||||
return mpt::IO::IsWriteSeekable(f);
|
||||
}
|
||||
IO::Offset TellWrite() override {
|
||||
return mpt::IO::TellWrite(f);
|
||||
}
|
||||
bool SeekBegin() override {
|
||||
return mpt::IO::SeekBegin(f);
|
||||
}
|
||||
bool SeekEnd() override {
|
||||
return mpt::IO::SeekEnd(f);
|
||||
}
|
||||
bool SeekAbsolute(IO::Offset pos) override {
|
||||
return mpt::IO::SeekAbsolute(f, pos);
|
||||
}
|
||||
bool SeekRelative(IO::Offset off) override {
|
||||
return mpt::IO::SeekRelative(f, off);
|
||||
}
|
||||
bool WriteRawImpl(mpt::const_byte_span data) override {
|
||||
return mpt::IO::WriteRawImpl(f, data);
|
||||
}
|
||||
bool Flush() override {
|
||||
return mpt::IO::Flush(f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class IOFileBase {
|
||||
protected:
|
||||
IOFileBase() = default;
|
||||
virtual ~IOFileBase() = default;
|
||||
|
||||
public:
|
||||
virtual bool IsValid() = 0;
|
||||
virtual bool IsReadSeekable() = 0;
|
||||
virtual bool IsWriteSeekable() = 0;
|
||||
virtual IO::Offset TellRead() = 0;
|
||||
virtual IO::Offset TellWrite() = 0;
|
||||
virtual bool SeekBegin() = 0;
|
||||
virtual bool SeekEnd() = 0;
|
||||
virtual bool SeekAbsolute(IO::Offset pos) = 0;
|
||||
virtual bool SeekRelative(IO::Offset off) = 0;
|
||||
virtual mpt::byte_span ReadRawImpl(mpt::byte_span data) = 0;
|
||||
virtual bool WriteRawImpl(mpt::const_byte_span data) = 0;
|
||||
virtual bool IsEof() = 0;
|
||||
virtual bool Flush() = 0;
|
||||
};
|
||||
|
||||
template <typename Tfile>
|
||||
class IOFile
|
||||
: public IOFileBase {
|
||||
private:
|
||||
Tfile & f;
|
||||
|
||||
public:
|
||||
IOFile(Tfile & f_)
|
||||
: f(f_) {
|
||||
}
|
||||
~IOFile() override = default;
|
||||
|
||||
public:
|
||||
bool IsValid() override {
|
||||
return mpt::IO::IsValid(f);
|
||||
}
|
||||
bool IsReadSeekable() override {
|
||||
return mpt::IO::IsReadSeekable(f);
|
||||
}
|
||||
bool IsWriteSeekable() override {
|
||||
return mpt::IO::IsWriteSeekable(f);
|
||||
}
|
||||
IO::Offset TellRead() override {
|
||||
return mpt::IO::TellRead(f);
|
||||
}
|
||||
IO::Offset TellWrite() override {
|
||||
return mpt::IO::TellWrite(f);
|
||||
}
|
||||
bool SeekBegin() override {
|
||||
return mpt::IO::SeekBegin(f);
|
||||
}
|
||||
bool SeekEnd() override {
|
||||
return mpt::IO::SeekEnd(f);
|
||||
}
|
||||
bool SeekAbsolute(IO::Offset pos) override {
|
||||
return mpt::IO::SeekAbsolute(f, pos);
|
||||
}
|
||||
bool SeekRelative(IO::Offset off) override {
|
||||
return mpt::IO::SeekRelative(f, off);
|
||||
}
|
||||
mpt::byte_span ReadRawImpl(mpt::byte_span data) override {
|
||||
return mpt::IO::ReadRawImpl(f, data);
|
||||
}
|
||||
bool WriteRawImpl(mpt::const_byte_span data) override {
|
||||
return mpt::IO::WriteRawImpl(f, data);
|
||||
}
|
||||
bool IsEof() override {
|
||||
return mpt::IO::IsEof(f);
|
||||
}
|
||||
bool Flush() override {
|
||||
return mpt::IO::Flush(f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Tfile>
|
||||
struct FileOperations<Tfile, typename std::enable_if_t<std::is_base_of<IFileBase, Tfile>::value>> {
|
||||
|
||||
private:
|
||||
IFileBase & f;
|
||||
|
||||
public:
|
||||
FileOperations(IFileBase & f_)
|
||||
: f(f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool IsValid() {
|
||||
return f.IsValid();
|
||||
}
|
||||
|
||||
inline bool IsReadSeekable() {
|
||||
return f.IsReadSeekable();
|
||||
}
|
||||
|
||||
inline IO::Offset TellRead() {
|
||||
return f.TellRead();
|
||||
}
|
||||
|
||||
inline bool SeekBegin() {
|
||||
return f.SeekBegin();
|
||||
}
|
||||
|
||||
inline bool SeekEnd() {
|
||||
return f.SeekEnd();
|
||||
}
|
||||
|
||||
inline bool SeekAbsolute(IO::Offset pos) {
|
||||
return f.SeekAbsolute(pos);
|
||||
}
|
||||
|
||||
inline bool SeekRelative(IO::Offset off) {
|
||||
return f.SeekRelative(off);
|
||||
}
|
||||
|
||||
inline mpt::byte_span ReadRawImpl(mpt::byte_span data) {
|
||||
return f.ReadRawImpl(data);
|
||||
}
|
||||
|
||||
inline bool IsEof() {
|
||||
return f.IsEof();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Tfile>
|
||||
struct FileOperations<Tfile, typename std::enable_if_t<std::is_base_of<OFileBase, Tfile>::value>> {
|
||||
|
||||
private:
|
||||
OFileBase & f;
|
||||
|
||||
public:
|
||||
FileOperations(OFileBase & f_)
|
||||
: f(f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool IsValid() {
|
||||
return f.IsValid();
|
||||
}
|
||||
|
||||
inline bool IsWriteSeekable() {
|
||||
return f.IsWriteSeekable();
|
||||
}
|
||||
|
||||
inline IO::Offset TellWrite() {
|
||||
return f.TellWrite();
|
||||
}
|
||||
|
||||
inline bool SeekBegin() {
|
||||
return f.SeekBegin();
|
||||
}
|
||||
|
||||
inline bool SeekEnd() {
|
||||
return f.SeekEnd();
|
||||
}
|
||||
|
||||
inline bool SeekAbsolute(IO::Offset pos) {
|
||||
return f.SeekAbsolute(pos);
|
||||
}
|
||||
|
||||
inline bool SeekRelative(IO::Offset off) {
|
||||
return f.SeekRelative(off);
|
||||
}
|
||||
|
||||
inline bool WriteRawImpl(mpt::const_byte_span data) {
|
||||
return f.WriteRawImpl(data);
|
||||
}
|
||||
|
||||
inline bool Flush() {
|
||||
return f.Flush();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Tfile>
|
||||
struct FileOperations<Tfile, typename std::enable_if_t<std::is_base_of<IOFileBase, Tfile>::value>> {
|
||||
|
||||
private:
|
||||
IOFileBase & f;
|
||||
|
||||
public:
|
||||
FileOperations(IOFileBase & f_)
|
||||
: f(f_) {
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
inline bool IsValid() {
|
||||
return f.IsValid();
|
||||
}
|
||||
|
||||
inline bool IsReadSeekable() {
|
||||
return f.IsReadSeekable();
|
||||
}
|
||||
|
||||
inline bool IsWriteSeekable() {
|
||||
return f.IsWriteSeekable();
|
||||
}
|
||||
|
||||
inline IO::Offset TellRead() {
|
||||
return f.TellRead();
|
||||
}
|
||||
|
||||
inline IO::Offset TellWrite() {
|
||||
return f.TellWrite();
|
||||
}
|
||||
|
||||
inline bool SeekBegin() {
|
||||
return f.SeekBegin();
|
||||
}
|
||||
|
||||
inline bool SeekEnd() {
|
||||
return f.SeekEnd();
|
||||
}
|
||||
|
||||
inline bool SeekAbsolute(IO::Offset pos) {
|
||||
return f.SeekAbsolute(pos);
|
||||
}
|
||||
|
||||
inline bool SeekRelative(IO::Offset off) {
|
||||
return f.SeekRelative(off);
|
||||
}
|
||||
|
||||
inline mpt::byte_span ReadRawImpl(mpt::byte_span data) {
|
||||
return f.ReadRawImpl(data);
|
||||
}
|
||||
|
||||
inline bool WriteRawImpl(mpt::const_byte_span data) {
|
||||
return f.WriteRawImpl(data);
|
||||
}
|
||||
|
||||
inline bool IsEof() {
|
||||
return f.IsEof();
|
||||
}
|
||||
|
||||
inline bool Flush() {
|
||||
return f.Flush();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
|
||||
|
||||
} // namespace MPT_INLINE_NS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#endif // MPT_IO_IO_VIRTUAL_WRAPPER_HPP
|
|
@ -0,0 +1,573 @@
|
|||
/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */
|
||||
|
||||
#ifndef MPT_IO_TESTS_IO_HPP
|
||||
#define MPT_IO_TESTS_IO_HPP
|
||||
|
||||
|
||||
|
||||
#include "mpt/base/integer.hpp"
|
||||
#include "mpt/base/namespace.hpp"
|
||||
#include "mpt/base/utility.hpp"
|
||||
#include "mpt/endian/integer.hpp"
|
||||
#include "mpt/io/base.hpp"
|
||||
#include "mpt/io/io.hpp"
|
||||
#include "mpt/io/io_stdstream.hpp"
|
||||
#include "mpt/test/test.hpp"
|
||||
#include "mpt/test/test_macros.hpp"
|
||||
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
inline namespace MPT_INLINE_NS {
|
||||
|
||||
|
||||
|
||||
namespace tests {
|
||||
namespace io {
|
||||
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
MPT_TEST_GROUP_INLINE("mpt/io")
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
{
|
||||
|
||||
// check that empty stringstream behaves correctly with our MSVC workarounds when using iostream interface directly
|
||||
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(ss.tellp(), std::streampos(0));
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss.seekp(0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true);
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss.seekp(0, std::ios_base::beg);
|
||||
MPT_TEST_EXPECT_EQUAL(!ss.fail(), true);
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss.seekp(0, std::ios_base::cur);
|
||||
MPT_TEST_EXPECT_EQUAL(!ss.fail(), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(ss.tellg(), std::streampos(0));
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
ss.seekg(0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
ss.seekg(0, std::ios_base::beg);
|
||||
MPT_TEST_EXPECT_EQUAL(!ss.fail(), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
ss.seekg(0, std::ios_base::cur);
|
||||
MPT_TEST_EXPECT_EQUAL(!ss.fail(), true);
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream s;
|
||||
char b = 23;
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.seekp(0, std::ios_base::beg);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.write(&b, 1);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(1));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.seekp(0, std::ios_base::beg);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.seekp(0, std::ios_base::end);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellp(), std::streampos(1));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.str(), std::string(1, b));
|
||||
}
|
||||
|
||||
{
|
||||
std::istringstream s;
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.seekg(0, std::ios_base::beg);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.seekg(0, std::ios_base::end);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
}
|
||||
|
||||
{
|
||||
std::istringstream s("a");
|
||||
char a = 0;
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.seekg(0, std::ios_base::beg);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.read(&a, 1);
|
||||
MPT_TEST_EXPECT_EQUAL(a, 'a');
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(1));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.seekg(0, std::ios_base::beg);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(0));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
s.seekg(0, std::ios_base::end);
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.tellg(), std::streampos(1));
|
||||
MPT_TEST_EXPECT_EQUAL(!s.fail(), true);
|
||||
MPT_TEST_EXPECT_EQUAL(std::string(1, a), std::string(1, 'a'));
|
||||
}
|
||||
|
||||
// check that empty native and fixed stringstream both behaves correctly with out IO functions
|
||||
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(ss), 0);
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(ss), true);
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true);
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekRelative(ss, 0), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(ss), 0);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(ss), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekRelative(ss, 0), true);
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(ss), 0);
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(ss), true);
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true);
|
||||
}
|
||||
{
|
||||
std::ostringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekRelative(ss, 0), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(ss), 0);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(ss), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekAbsolute(ss, 0), true);
|
||||
}
|
||||
{
|
||||
std::istringstream ss;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekRelative(ss, 0), true);
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream s;
|
||||
char b = 23;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteRaw(s, &b, 1), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 1);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 1);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.str(), std::string(1, b));
|
||||
}
|
||||
|
||||
{
|
||||
std::istringstream s;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
}
|
||||
|
||||
{
|
||||
std::istringstream s("a");
|
||||
char a = 0;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadRaw(s, &a, 1).size(), 1u);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 1);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 1);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(std::string(1, a), std::string(1, 'a'));
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream s;
|
||||
char b = 23;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteRaw(s, &b, 1), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 1);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(s), 1);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(s.str(), std::string(1, b));
|
||||
}
|
||||
|
||||
{
|
||||
std::istringstream s;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
}
|
||||
|
||||
{
|
||||
std::istringstream s("a");
|
||||
char a = 0;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadRaw(s, &a, 1).size(), 1u);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 1);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekBegin(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 0);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::SeekEnd(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellRead(s), 1);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::IsValid(s), true);
|
||||
MPT_TEST_EXPECT_EQUAL(std::string(1, a), std::string(1, 'a'));
|
||||
}
|
||||
|
||||
// General file I/O tests
|
||||
{
|
||||
// Verify that writing arrays does not confuse the compiler.
|
||||
// This is both, compile-time and run-time cheking.
|
||||
// Run-time in case some weird compiler gets confused by our templates
|
||||
// and only writes the first array element.
|
||||
std::ostringstream f;
|
||||
uint16be data[2];
|
||||
mpt::reset(data);
|
||||
data[0] = 0x1234;
|
||||
data[1] = 0x5678;
|
||||
mpt::IO::Write(f, data);
|
||||
MPT_TEST_EXPECT_EQUAL(f.str(), std::string("\x12\x34\x56\x78"));
|
||||
}
|
||||
{
|
||||
std::ostringstream f;
|
||||
std::vector<int16be> data;
|
||||
data.resize(3);
|
||||
data[0] = 0x1234;
|
||||
data[1] = 0x5678;
|
||||
data[2] = 0x1234;
|
||||
mpt::IO::Write(f, data);
|
||||
MPT_TEST_EXPECT_EQUAL(f.str(), std::string("\x12\x34\x56\x78\x12\x34"));
|
||||
}
|
||||
{
|
||||
std::ostringstream f;
|
||||
int16be data[3];
|
||||
mpt::reset(data);
|
||||
data[0] = 0x1234;
|
||||
data[1] = 0x5678;
|
||||
data[2] = 0x1234;
|
||||
mpt::IO::Write(f, data);
|
||||
MPT_TEST_EXPECT_EQUAL(f.str(), std::string("\x12\x34\x56\x78\x12\x34"));
|
||||
}
|
||||
|
||||
{
|
||||
auto TestAdaptive16 = [&](uint16 value, mpt::IO::Offset expected_size, std::size_t fixedSize, const char * bytes) {
|
||||
std::stringstream f;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteAdaptiveInt16LE(f, value, fixedSize), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(f), expected_size);
|
||||
if (bytes) {
|
||||
mpt::IO::SeekBegin(f);
|
||||
for (mpt::IO::Offset i = 0; i < expected_size; ++i) {
|
||||
uint8 val = 0;
|
||||
mpt::IO::ReadIntLE<uint8>(f, val);
|
||||
MPT_TEST_EXPECT_EQUAL(val, static_cast<uint8>(bytes[i]));
|
||||
}
|
||||
}
|
||||
mpt::IO::SeekBegin(f);
|
||||
uint16 result = 0;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadAdaptiveInt16LE(f, result), true);
|
||||
MPT_TEST_EXPECT_EQUAL(result, value);
|
||||
};
|
||||
auto TestAdaptive32 = [&](uint32 value, mpt::IO::Offset expected_size, std::size_t fixedSize, const char * bytes) {
|
||||
std::stringstream f;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteAdaptiveInt32LE(f, value, fixedSize), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(f), expected_size);
|
||||
if (bytes) {
|
||||
mpt::IO::SeekBegin(f);
|
||||
for (mpt::IO::Offset i = 0; i < expected_size; ++i) {
|
||||
uint8 val = 0;
|
||||
mpt::IO::ReadIntLE<uint8>(f, val);
|
||||
MPT_TEST_EXPECT_EQUAL(val, static_cast<uint8>(bytes[i]));
|
||||
}
|
||||
}
|
||||
mpt::IO::SeekBegin(f);
|
||||
uint32 result = 0;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadAdaptiveInt32LE(f, result), true);
|
||||
MPT_TEST_EXPECT_EQUAL(result, value);
|
||||
};
|
||||
auto TestAdaptive64 = [&](uint64 value, mpt::IO::Offset expected_size, std::size_t fixedSize, const char * bytes) {
|
||||
std::stringstream f;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::WriteAdaptiveInt64LE(f, value, fixedSize), true);
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::TellWrite(f), expected_size);
|
||||
if (bytes) {
|
||||
mpt::IO::SeekBegin(f);
|
||||
for (mpt::IO::Offset i = 0; i < expected_size; ++i) {
|
||||
uint8 val = 0;
|
||||
mpt::IO::ReadIntLE<uint8>(f, val);
|
||||
MPT_TEST_EXPECT_EQUAL(val, static_cast<uint8>(bytes[i]));
|
||||
}
|
||||
}
|
||||
mpt::IO::SeekBegin(f);
|
||||
uint64 result = 0;
|
||||
MPT_TEST_EXPECT_EQUAL(mpt::IO::ReadAdaptiveInt64LE(f, result), true);
|
||||
MPT_TEST_EXPECT_EQUAL(result, value);
|
||||
};
|
||||
TestAdaptive16(0, 1, 0, "\x00");
|
||||
TestAdaptive16(1, 1, 0, "\x02");
|
||||
TestAdaptive16(2, 1, 0, nullptr);
|
||||
TestAdaptive16(0x7f, 1, 0, nullptr);
|
||||
TestAdaptive16(0x80, 2, 0, "\x01\x01");
|
||||
TestAdaptive16(0x81, 2, 0, "\x03\x01");
|
||||
TestAdaptive16(0x7fff, 2, 0, "\xff\xff");
|
||||
TestAdaptive16(0, 1, 1, nullptr);
|
||||
TestAdaptive16(1, 1, 1, nullptr);
|
||||
TestAdaptive16(2, 1, 1, nullptr);
|
||||
TestAdaptive16(0x7f, 1, 1, nullptr);
|
||||
TestAdaptive16(0x80, 2, 0, nullptr);
|
||||
TestAdaptive16(0x81, 2, 0, nullptr);
|
||||
TestAdaptive16(0x7fff, 2, 0, nullptr);
|
||||
TestAdaptive16(0, 2, 2, "\x01\x00");
|
||||
TestAdaptive16(1, 2, 2, "\x03\x00");
|
||||
TestAdaptive16(2, 2, 2, nullptr);
|
||||
TestAdaptive16(0x7f, 2, 2, nullptr);
|
||||
TestAdaptive16(0x80, 2, 2, nullptr);
|
||||
TestAdaptive16(0x81, 2, 2, nullptr);
|
||||
TestAdaptive16(0x7fff, 2, 2, nullptr);
|
||||
|
||||
TestAdaptive32(0, 1, 0, "\x00");
|
||||
TestAdaptive32(1, 1, 0, nullptr);
|
||||
TestAdaptive32(2, 1, 0, nullptr);
|
||||
TestAdaptive32(0x3f, 1, 0, nullptr);
|
||||
TestAdaptive32(0x40, 2, 0, "\x01\x01");
|
||||
TestAdaptive32(0x41, 2, 0, "\x05\x01");
|
||||
TestAdaptive32(0x7f, 2, 0, nullptr);
|
||||
TestAdaptive32(0x80, 2, 0, nullptr);
|
||||
TestAdaptive32(0x3fff, 2, 0, nullptr);
|
||||
TestAdaptive32(0x4000, 3, 0, "\x02\x00\x01");
|
||||
TestAdaptive32(0x4001, 3, 0, nullptr);
|
||||
TestAdaptive32(0x3fffff, 3, 0, nullptr);
|
||||
TestAdaptive32(0x400000, 4, 0, "\x03\x00\x00\x01");
|
||||
TestAdaptive32(0x400001, 4, 0, nullptr);
|
||||
TestAdaptive32(0x3fffffff, 4, 0, "\xff\xff\xff\xff");
|
||||
TestAdaptive32(0, 2, 2, nullptr);
|
||||
TestAdaptive32(1, 2, 2, nullptr);
|
||||
TestAdaptive32(2, 2, 2, nullptr);
|
||||
TestAdaptive32(0x3f, 2, 2, nullptr);
|
||||
TestAdaptive32(0x40, 2, 2, nullptr);
|
||||
TestAdaptive32(0x41, 2, 2, nullptr);
|
||||
TestAdaptive32(0x7f, 2, 2, nullptr);
|
||||
TestAdaptive32(0x80, 2, 2, nullptr);
|
||||
TestAdaptive32(0x3fff, 2, 2, nullptr);
|
||||
TestAdaptive32(0, 3, 3, nullptr);
|
||||
TestAdaptive32(1, 3, 3, nullptr);
|
||||
TestAdaptive32(2, 3, 3, nullptr);
|
||||
TestAdaptive32(0x3f, 3, 3, nullptr);
|
||||
TestAdaptive32(0x40, 3, 3, nullptr);
|
||||
TestAdaptive32(0x41, 3, 3, nullptr);
|
||||
TestAdaptive32(0x7f, 3, 3, nullptr);
|
||||
TestAdaptive32(0x80, 3, 3, nullptr);
|
||||
TestAdaptive32(0x3fff, 3, 3, nullptr);
|
||||
TestAdaptive32(0x4000, 3, 3, nullptr);
|
||||
TestAdaptive32(0x4001, 3, 3, nullptr);
|
||||
TestAdaptive32(0x3fffff, 3, 3, nullptr);
|
||||
TestAdaptive32(0, 4, 4, nullptr);
|
||||
TestAdaptive32(1, 4, 4, nullptr);
|
||||
TestAdaptive32(2, 4, 4, nullptr);
|
||||
TestAdaptive32(0x3f, 4, 4, nullptr);
|
||||
TestAdaptive32(0x40, 4, 4, nullptr);
|
||||
TestAdaptive32(0x41, 4, 4, nullptr);
|
||||
TestAdaptive32(0x7f, 4, 4, nullptr);
|
||||
TestAdaptive32(0x80, 4, 4, nullptr);
|
||||
TestAdaptive32(0x3fff, 4, 4, nullptr);
|
||||
TestAdaptive32(0x4000, 4, 4, nullptr);
|
||||
TestAdaptive32(0x4001, 4, 4, nullptr);
|
||||
TestAdaptive32(0x3fffff, 4, 4, nullptr);
|
||||
TestAdaptive32(0x400000, 4, 4, nullptr);
|
||||
TestAdaptive32(0x400001, 4, 4, nullptr);
|
||||
TestAdaptive32(0x3fffffff, 4, 4, nullptr);
|
||||
|
||||
TestAdaptive64(0, 1, 0, nullptr);
|
||||
TestAdaptive64(1, 1, 0, nullptr);
|
||||
TestAdaptive64(2, 1, 0, nullptr);
|
||||
TestAdaptive64(0x3f, 1, 0, nullptr);
|
||||
TestAdaptive64(0x40, 2, 0, nullptr);
|
||||
TestAdaptive64(0x41, 2, 0, nullptr);
|
||||
TestAdaptive64(0x7f, 2, 0, nullptr);
|
||||
TestAdaptive64(0x80, 2, 0, nullptr);
|
||||
TestAdaptive64(0x3fff, 2, 0, nullptr);
|
||||
TestAdaptive64(0x4000, 4, 0, nullptr);
|
||||
TestAdaptive64(0x4001, 4, 0, nullptr);
|
||||
TestAdaptive64(0x3fffff, 4, 0, nullptr);
|
||||
TestAdaptive64(0x400000, 4, 0, nullptr);
|
||||
TestAdaptive64(0x400001, 4, 0, nullptr);
|
||||
TestAdaptive64(0x3fffffff, 4, 0, nullptr);
|
||||
TestAdaptive64(0x40000000, 8, 0, nullptr);
|
||||
TestAdaptive64(0x40000001, 8, 0, nullptr);
|
||||
TestAdaptive64(0x3fffffffffffffffull, 8, 0, nullptr);
|
||||
TestAdaptive64(0, 2, 2, nullptr);
|
||||
TestAdaptive64(1, 2, 2, nullptr);
|
||||
TestAdaptive64(2, 2, 2, nullptr);
|
||||
TestAdaptive64(0x3f, 2, 2, nullptr);
|
||||
TestAdaptive64(0, 4, 4, nullptr);
|
||||
TestAdaptive64(1, 4, 4, nullptr);
|
||||
TestAdaptive64(2, 4, 4, nullptr);
|
||||
TestAdaptive64(0x3f, 4, 4, nullptr);
|
||||
TestAdaptive64(0x40, 4, 4, nullptr);
|
||||
TestAdaptive64(0x41, 4, 4, nullptr);
|
||||
TestAdaptive64(0x7f, 4, 4, nullptr);
|
||||
TestAdaptive64(0x80, 4, 4, nullptr);
|
||||
TestAdaptive64(0x3fff, 4, 4, nullptr);
|
||||
TestAdaptive64(0, 8, 8, nullptr);
|
||||
TestAdaptive64(1, 8, 8, nullptr);
|
||||
TestAdaptive64(2, 8, 8, nullptr);
|
||||
TestAdaptive64(0x3f, 8, 8, nullptr);
|
||||
TestAdaptive64(0x40, 8, 8, nullptr);
|
||||
TestAdaptive64(0x41, 8, 8, nullptr);
|
||||
TestAdaptive64(0x7f, 8, 8, nullptr);
|
||||
TestAdaptive64(0x80, 8, 8, nullptr);
|
||||
TestAdaptive64(0x3fff, 8, 8, nullptr);
|
||||
TestAdaptive64(0x4000, 8, 8, nullptr);
|
||||
TestAdaptive64(0x4001, 8, 8, nullptr);
|
||||
TestAdaptive64(0x3fffff, 8, 8, nullptr);
|
||||
TestAdaptive64(0x400000, 8, 8, nullptr);
|
||||
TestAdaptive64(0x400001, 8, 8, nullptr);
|
||||
TestAdaptive64(0x3fffffff, 8, 8, nullptr);
|
||||
TestAdaptive64(0x40000000, 8, 8, nullptr);
|
||||
TestAdaptive64(0x40000001, 8, 8, nullptr);
|
||||
TestAdaptive64(0x3fffffffffffffffull, 8, 8, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace tests
|
||||
|
||||
|
||||
|
||||
} // namespace MPT_INLINE_NS
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#endif // MPT_IO_TESTS_IO_HPP
|
Loading…
Add table
Add a link
Reference in a new issue