1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
#pragma once
#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ < 24
// Android fully supports 64-bit file offsets only for API 24 and above.
#elif !defined(DOXYGEN_GENERATING_OUTPUT)
# define _FILE_OFFSET_BITS 64
#endif
// Enable newer ABI on Mac OS 10.5 and later, which is needed for struct stat to have birthtime members
#if defined(__APPLE__) || defined(__MACH__)
# define _DARWIN_USE_64_BIT_INODE 1
#endif
#include "../Common.h"
#include "../Base/IDisposable.h"
#if defined(DEATH_TARGET_BIG_ENDIAN)
# include "../Base/Memory.h"
#endif
#include <type_traits>
namespace Death { namespace IO {
//###==##====#=====--==~--~=~- --- -- - - - -
/**
@brief Specifies the position in a stream to use for seeking
*/
enum class SeekOrigin {
/** @brief Specifies the beginning of a stream */
Begin,
/** @brief Specifies the current position within a stream */
Current,
/** @brief Specifies the end of a stream */
End
};
/**
@brief Provides a generic view of a sequence of bytes
*/
class Stream : public IDisposable
{
public:
enum {
/** @brief Returned if @ref Stream doesn't point to valid source */
Invalid = -1,
/** @brief Returned if one of the parameters provided to a method is not valid */
OutOfRange = -2,
/** @brief Returned if seek operation is not supported by @ref Stream or the stream length is unknown */
NotSeekable = -3
};
/** @brief Whether the stream has been sucessfully opened */
explicit operator bool() {
return IsValid();
}
/** @brief Closes the stream and releases all assigned resources */
virtual void Dispose() = 0;
/** @brief Seeks in an opened stream */
virtual std::int64_t Seek(std::int64_t offset, SeekOrigin origin) = 0;
/** @brief Tells the seek position of an opened stream */
virtual std::int64_t GetPosition() const = 0;
/** @brief Reads a certain amount of bytes from the stream to a buffer */
virtual std::int64_t Read(void* destination, std::int64_t bytesToRead) = 0;
/** @brief Writes a certain amount of bytes from a buffer to the stream */
virtual std::int64_t Write(const void* source, std::int64_t bytesToWrite) = 0;
/** @brief Clears all buffers for this stream and causes any buffered data to be written to the underlying device */
virtual bool Flush() = 0;
/** @brief Returns `true` if the stream has been sucessfully opened */
virtual bool IsValid() = 0;
/** @brief Returns stream size in bytes */
virtual std::int64_t GetSize() const = 0;
/** @brief Sets stream size in bytes */
virtual std::int64_t SetSize(std::int64_t size) = 0;
/** @brief Reads the bytes from the current stream and writes them to the target stream */
std::int64_t CopyTo(Stream& targetStream);
/** @brief Reads a trivial value from the stream */
template<typename T>
DEATH_ALWAYS_INLINE T ReadValue()
{
static_assert(std::is_trivially_copyable<T>::value, "ReadValue() requires the source type to be trivially copyable");
static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "ReadValue() must not be used on pointer or reference types");
T value{};
Read(&value, sizeof(T));
return value;
}
/** @brief Writes a trivial value to the stream */
template<typename T>
DEATH_ALWAYS_INLINE void WriteValue(const T& value)
{
static_assert(std::is_trivially_copyable<T>::value, "WriteValue() requires the source type to be trivially copyable");
static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "WriteValue() must not be used on pointer or reference types");
Write(&value, sizeof(T));
}
/** @brief Reads a trivial value from the stream always as Little-Endian */
template<typename T>
DEATH_ALWAYS_INLINE T ReadValueAsLE()
{
static_assert(std::is_trivially_copyable<T>::value, "ReadValueAsLE() requires the source type to be trivially copyable");
static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "ReadValueAsLE() must not be used on pointer or reference types");
static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "ReadValueAsLE() requires the source type to be 2, 4 or 8 bytes");
T value{};
Read(&value, sizeof(T));
#if defined(DEATH_TARGET_BIG_ENDIAN)
value = Memory::SwapBytes(value);
#endif
return value;
}
/** @brief Writes a trivial value to the stream always as Little-Endian */
template<typename T>
DEATH_ALWAYS_INLINE void WriteValueAsLE(T value)
{
static_assert(std::is_trivially_copyable<T>::value, "WriteValueAsLE() requires the source type to be trivially copyable");
static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "WriteValueAsLE() must not be used on pointer or reference types");
static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "WriteValueAsLE() requires the source type to be 2, 4 or 8 bytes");
#if defined(DEATH_TARGET_BIG_ENDIAN)
value = Memory::SwapBytes(value);
#endif
Write(&value, sizeof(T));
}
/** @brief Reads a 32-bit integer value from the stream using variable-length quantity encoding */
std::int32_t ReadVariableInt32();
/** @brief Reads a 64-bit integer value from the stream using variable-length quantity encoding */
std::int64_t ReadVariableInt64();
/** @brief Reads a 32-bit unsigned integer value from the stream using variable-length quantity encoding */
std::uint32_t ReadVariableUint32();
/** @brief Reads a 64-bit unsigned integer value from the stream using variable-length quantity encoding */
std::uint64_t ReadVariableUint64();
/** @brief Writes a 32-bit integer value to the stream using variable-length quantity encoding */
std::int64_t WriteVariableInt32(std::int32_t value);
/** @brief Writes a 64-bit integer value to the stream using variable-length quantity encoding */
std::int64_t WriteVariableInt64(std::int64_t value);
/** @brief Writes a 32-bit unsigned integer value to the stream using variable-length quantity encoding */
std::int64_t WriteVariableUint32(std::uint32_t value);
/** @brief Writes a 64-bit unsigned integer value to the stream using variable-length quantity encoding */
std::int64_t WriteVariableUint64(std::uint64_t value);
};
}}
|