Move dependencies to the top level.

This commit is contained in:
jakcron
2022-04-16 18:27:14 +08:00
parent b67980d3d2
commit 5d62e839e7
844 changed files with 74 additions and 114431 deletions
-110
View File
@@ -1,110 +0,0 @@
#include <tc/ByteData.h>
const std::string tc::ByteData::kClassName = "tc::ByteData";
tc::ByteData::ByteData() :
ByteData(0)
{}
tc::ByteData::ByteData(const tc::ByteData& other) :
ByteData(other.mPtr.get(), other.mSize)
{}
tc::ByteData::ByteData(tc::ByteData&& other) :
mSize(other.mSize),
mPtr(std::move(other.mPtr))
{
other.mSize = 0;
}
tc::ByteData::ByteData(std::initializer_list<byte_t> l) :
ByteData(l.size(), false)
{
size_t i = 0;
for (auto itr = l.begin(); itr != l.end(); itr++, i++)
{
mPtr.get()[i] = *itr;
}
}
tc::ByteData::ByteData(size_t size, bool clear_memory)
{
if (size == 0)
{
mPtr.reset();
}
else
{
try
{
mPtr = std::unique_ptr<byte_t>(new byte_t[size]);
}
catch (const std::bad_alloc&)
{
throw tc::OutOfMemoryException(kClassName, "std::bad_alloc thrown");
}
if (mPtr == nullptr)
{
throw tc::OutOfMemoryException(kClassName, "Failed to allocate memory");
}
}
mSize = size;
if (clear_memory == true)
{
memset(mPtr.get(), 0, mSize);
}
}
tc::ByteData::ByteData(const byte_t* data, size_t size) :
ByteData(size, false)
{
memcpy(mPtr.get(), data, mSize);
}
tc::ByteData& tc::ByteData::operator=(const ByteData& other)
{
*this = tc::ByteData(other);
return *this;
}
tc::ByteData& tc::ByteData::operator=(ByteData&& other)
{
this->mPtr = std::move(other.mPtr);
this->mSize = other.mSize;
other.mSize = 0;
return *this;
}
byte_t& tc::ByteData::operator[](size_t index)
{
return mPtr.get()[index];
}
byte_t tc::ByteData::operator[](size_t index) const
{
return mPtr.get()[index];
}
bool tc::ByteData::operator==(const ByteData& other) const
{
return (this->mSize == other.mSize && memcmp(this->mPtr.get(), other.mPtr.get(), this->mSize) == 0);
}
bool tc::ByteData::operator!=(const ByteData& other) const
{
return !(*this == other);
}
byte_t* tc::ByteData::data() const
{
return mPtr.get();
}
size_t tc::ByteData::size() const
{
return mPtr == nullptr ? 0 : mSize;
}
@@ -1,46 +0,0 @@
#include <tc/Exception.h>
tc::Exception::Exception() noexcept :
what_(""),
module_(""),
error_("")
{
}
tc::Exception::Exception(const std::string & what) noexcept :
what_(what),
module_(""),
error_(what)
{
}
tc::Exception::Exception(const std::string & module, const std::string & what) noexcept :
what_(""),
module_(module),
error_(what)
{
if (module_.length() > 0)
{
what_ = "[" + module_ + " ERROR] " + error_;
}
else
{
what_ = error_;
}
}
const char* tc::Exception::what() const noexcept
{
return what_.c_str();
}
const char* tc::Exception::module() const noexcept
{
return module_.c_str();
}
const char * tc::Exception::error() const noexcept
{
return error_.c_str();
}
@@ -1,41 +0,0 @@
#include <tc/PlatformErrorHandlingUtil.h>
#include <algorithm>
#ifdef _WIN32
std::string tc::PlatformErrorHandlingUtil::GetLastErrorString(DWORD error)
{
if (error)
{
LPVOID lpMsgBuf;
DWORD bufLen = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
if (bufLen)
{
LPCSTR lpMsgStr = (LPCSTR)lpMsgBuf;
std::string result(lpMsgStr, lpMsgStr+bufLen);
LocalFree(lpMsgBuf);
// remove CR+LF from string
result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
result.erase(std::remove(result.begin(), result.end(), '\r'), result.end());
return result;
}
}
return std::string();
}
#else
std::string tc::PlatformErrorHandlingUtil::GetGnuErrorNumString(int errnum)
{
return std::string(strerror(errnum));
}
#endif
@@ -1,222 +0,0 @@
#include <tc/cli/FormatUtil.h>
#include <fmt/core.h>
inline int charToByte(char chr)
{
if (chr >= 'a' && chr <= 'f')
return (chr - 'a') + 0xa;
else if (chr >= 'A' && chr <= 'F')
return (chr - 'A') + 0xa;
else if (chr >= '0' && chr <= '9')
return chr - '0';
return -1;
}
tc::ByteData tc::cli::FormatUtil::hexStringToBytes(const std::string& str)
{
size_t size = str.size();
if ((size % 2))
{
return tc::ByteData();
}
auto bytes = tc::ByteData(size/2);
for (size_t i = 0; i < bytes.size(); i++)
{
int byte = 0;
byte = charToByte(str[i * 2]);
if (byte == -1)
return tc::ByteData();
bytes.data()[i] = byte_t((byte & 0xf) << 4);
byte = charToByte(str[(i * 2) + 1]);
if (byte == -1)
return tc::ByteData();
bytes.data()[i] |= byte_t((byte & 0xf) << 0);
}
return bytes;
}
std::string tc::cli::FormatUtil::formatBytesAsStringWithLineLimit(const byte_t* data, size_t len, bool upper_case, const std::string& delimiter, size_t row_len, size_t indent_len, bool print_first_indent)
{
// create indentation string
std::string indent_str = "";
for (size_t i = 0; i < indent_len; i++)
{
indent_str += " ";
}
const byte_t* original_data = data;
// create output string
std::string output_str = "";
for (size_t print_len = 0; len > 0; len -= print_len, data += print_len)
{
if (data != original_data || print_first_indent)
{
output_str += indent_str;
}
print_len = std::min<size_t>(len, row_len);
output_str += formatBytesAsString(data, print_len, upper_case, delimiter);
output_str += fmt::format("\n");
}
return output_str;
}
std::string tc::cli::FormatUtil::formatBytesAsString(const byte_t* data, size_t size, bool upper_case, const std::string& delimiter)
{
// create output string
std::string output_str;
for (size_t i = 0; i < size; i++)
{
output_str += fmt::format((upper_case ? "{:02X}" : "{:02x}"), data[i]);
if (i+1 < size)
{
output_str += delimiter;
}
}
return output_str;
}
std::string tc::cli::FormatUtil::formatBytesAsString(const tc::ByteData& data, bool upper_case, const std::string& delimiter)
{
return formatBytesAsString(data.data(), data.size(), upper_case, delimiter);
}
std::string tc::cli::FormatUtil::formatListWithLineLimit(const std::vector<std::string>& str_list, size_t row_len, size_t indent_len, bool print_first_indent)
{
if (str_list.size() == 0)
{
return "";
}
// create output string
std::string output_str = "";
// create indentation string
std::string indent_str = "";
for (size_t i = 0; i < indent_len; i++)
{
indent_str += " ";
}
// create delimiter string
std::string delimiter_str = ", ";
size_t printed_len = 0;
for (auto itr = str_list.begin(); itr != str_list.end(); itr++)
{
// format the strings
// wrap the line after row_len multples
if (printed_len > row_len || printed_len == 0)
{
// don't print the new line if this is the first string
if (itr != str_list.begin())
{
output_str += fmt::format("{:s}\n", delimiter_str);
}
// print indent if this isn't the first string or the user has opted into printing the indent regardless
if (itr != str_list.begin() || print_first_indent)
{
output_str += indent_str;
}
// reset printed_len
printed_len = 0;
}
// within a line we want to separate the next string from the last one with a comma and a space
else
{
//ss << delimiter_str;
output_str += delimiter_str;
}
// print string
output_str += *itr;
// note the length of the string printed
printed_len += itr->size() + delimiter_str.size();
}
output_str += fmt::format("\n");
return output_str;
}
std::string tc::cli::FormatUtil::formatBytesAsHxdHexString(const byte_t* data, size_t size, size_t bytes_per_row, size_t byte_group_size)
{
if (size == 0 || bytes_per_row == 0 || byte_group_size == 0)
{
return "";
}
// create output string
std::string output_str = "";
// iterate over blocks
for (size_t i = 0; size > 0; i++)
{
size_t row_print_len = std::min<size_t>(size, bytes_per_row);
output_str += fmt::format("{:08x} | ", uint64_t(i) * uint64_t(bytes_per_row));
// for block i print each byte
for (size_t j = 0; j < bytes_per_row; j++)
{
if (j < row_print_len)
{
output_str += fmt::format("{:02X}", data[(i * bytes_per_row) + j]);
}
else
{
output_str += " ";
}
if (((j+1) % byte_group_size) == 0)
{
output_str += " ";
}
}
output_str += " ";
for (size_t j = 0; j < bytes_per_row; j++)
{
if (j < row_print_len)
{
byte_t byte = data[(i * bytes_per_row) + j];
output_str += fmt::format("{:c}", (iscntrl(byte) == 0 && byte < 0x7f) ? (char)byte : '.');
}
else
{
output_str += " ";
}
}
output_str += fmt::format("\n");
size -= row_print_len;
}
return output_str;
}
std::string tc::cli::FormatUtil::formatBytesAsHxdHexString(const byte_t* data, size_t size)
{
return formatBytesAsHxdHexString(data, size, 0x10, 1);
}
@@ -1,185 +0,0 @@
#include <tc/cli/OptionParser.h>
#include <fmt/core.h>
const std::string tc::cli::OptionParser::kClassName = "tc::cli::OptionParser";
tc::cli::OptionParser::OptionParser() :
mOptionaAliasMap(),
mUnkOptHandler(nullptr)
{
}
void tc::cli::OptionParser::registerOptionHandler(const std::shared_ptr<IOptionHandler>& handler)
{
if (handler == nullptr)
{
// throw exception
throw tc::ArgumentNullException(kClassName, "OptionHandler was null.");
}
if (handler->getOptionStrings().empty() && handler->getOptionRegexPatterns().empty())
{
throw tc::ArgumentOutOfRangeException(kClassName, "OptionHandler had no option strings or regex patterns.");
}
for (auto itr = handler->getOptionStrings().begin(); itr != handler->getOptionStrings().end(); itr++)
{
mOptionaAliasMap.insert(std::pair<std::string, std::shared_ptr<IOptionHandler>>(*itr, handler));
}
for (auto itr = handler->getOptionRegexPatterns().begin(); itr != handler->getOptionRegexPatterns().end(); itr++)
{
mOptionRegexList.push_back(std::pair<std::regex, std::shared_ptr<IOptionHandler>>(std::regex(*itr), handler));
}
}
void tc::cli::OptionParser::registerUnrecognisedOptionHandler(const std::shared_ptr<IOptionHandler>& handler)
{
if (handler == nullptr)
{
// throw exception
throw tc::ArgumentNullException(kClassName, "OptionHandler was null.");
}
mUnkOptHandler = handler;
}
void tc::cli::OptionParser::processOptions(const std::vector<std::string>& args)
{
/*
fmt::print("OptionParser\n");
fmt::print(" args:\n");
for (auto itr = args.begin(); itr != args.end(); itr++)
{
fmt::print(" #{:s}#\n", *itr);
}
*/
//fmt::print("Begin parsing options\n");
std::string opt = std::string();
std::vector<std::string> params = std::vector<std::string>();
for (auto itr = args.begin(); itr != args.end(); itr++)
{
//fmt::print("itr={:s}\n", *itr);
// (1) parse the current string
std::string tmp_opt = std::string();
std::string tmp_param = std::string();
bool is_compound = false;
// if the string begins with '-' then it is an option (which may be compound)
if (itr->compare(0,1,"-") == 0)
{
//fmt::print("looks like an option\n");
// if there is an "=" in this, then this is a compound option & paramter
size_t equalsign_pos = itr->find('=');
if (equalsign_pos == std::string::npos)
{
//fmt::print("the option looks like a solo option\n");
tmp_opt = *itr;
}
else
{
//fmt::print("the option looks like a compound opt=param\n");
tmp_opt = itr->substr(0, equalsign_pos);
tmp_param = itr->substr(equalsign_pos + 1, std::string::npos);
//fmt::print(" > opt : {:s}\n", tmp_opt);
//fmt::print(" > param : {:s}\n", tmp_param);
// --path=here
// 0123456789a
// --path : pos=0, size = 6 = equalsign_pos
// here : pos = 7 = eqialsign_pos + 1, size = 4 = 11 - 7 = itr->length() -(equalsign_pos+1)
is_compound = true;
}
}
// otherwise it is a param
else
{
tmp_param = *itr;
}
// (2) interprete it in the context of the current state
// the user has indicated the end of the current option
// hand off to option handler and clear state
if (opt.empty() == false && tmp_opt.empty() == false)
{
handleOption(opt, params);
opt = std::string();
params = std::vector<std::string>();
}
// if tmp_opt isn't empty then make it the option
if (tmp_opt.empty() == false)
{
opt = tmp_opt;
}
// if tmp_param isn't empty then add it to the param list
if (tmp_param.empty() == false)
{
// if there is no option set, then this is a head-less parameter, throw exception
if (opt.empty() == true)
{
throw tc::ArgumentException(kClassName, "Option parameter was provided without an option.");
}
params.push_back(tmp_param);
}
// compound options only accept one parameter
if (is_compound)
{
handleOption(opt, params);
opt = std::string();
params = std::vector<std::string>();
}
}
// process dangling opt/params
if (opt.empty() == false)
{
handleOption(opt, params);
}
}
void tc::cli::OptionParser::processOptions(const std::vector<std::string>& args, size_t pos, size_t num)
{
processOptions({args.begin()+pos, args.begin()+pos+num});
}
void tc::cli::OptionParser::handleOption(const std::string& opt, const std::vector<std::string>& params)
{
// attempt to locate a literal alias
auto aliasItr = mOptionaAliasMap.find(opt);
if (aliasItr != mOptionaAliasMap.end())
{
aliasItr->second->processOption(opt, params);
return;
}
// attempt to pattern match
for (auto regexItr = mOptionRegexList.begin(); regexItr != mOptionRegexList.end(); regexItr++)
{
if (std::regex_match(opt, regexItr->first))
{
regexItr->second->processOption(opt, params);
return;
}
}
// attempt to use unknown option handler
if (mUnkOptHandler != nullptr)
{
mUnkOptHandler->processOption(opt, params);
return;
}
// if no handler is located, throw exception
throw tc::ArgumentException(kClassName, fmt::format("Option \"{}\" is not recognised.", opt));
}
@@ -1,328 +0,0 @@
#include <tc/crypto/Aes128CbcEncryptedStream.h>
#include <tc/io/IOUtil.h>
#include <tc/io/StreamUtil.h>
/*
#include <fmt/core.h>
#include <tc/cli/FormatUtil.h>
*/
// inline utils
inline uint64_t castInt64ToUint64(int64_t val) { return val < 0 ? 0 : uint64_t(val); }
inline int64_t castUint64ToInt64(uint64_t val) { return (int64_t)std::min<uint64_t>(val, uint64_t(std::numeric_limits<int64_t>::max())); }
inline uint64_t offsetToBlockIndex(int64_t offset) { return castInt64ToUint64(offset / tc::io::IOUtil::castSizeToInt64(tc::crypto::Aes128CbcEncryptor::kBlockSize)); };
inline int64_t blockIndexToOffset(uint64_t block_index) { return castUint64ToInt64(block_index) * tc::io::IOUtil::castSizeToInt64(tc::crypto::Aes128CbcEncryptor::kBlockSize); };
inline size_t lengthToBlockNum(int64_t length) { return tc::io::IOUtil::castInt64ToSize(length / tc::io::IOUtil::castSizeToInt64(tc::crypto::Aes128CbcEncryptor::kBlockSize)); };
inline size_t offsetInBlock(int64_t offset) { return tc::io::IOUtil::castInt64ToSize(offset % tc::io::IOUtil::castSizeToInt64(tc::crypto::Aes128CbcEncryptor::kBlockSize)); };
const std::string tc::crypto::Aes128CbcEncryptedStream::kClassName = "tc::crypto::Aes128CbcEncryptedStream";
tc::crypto::Aes128CbcEncryptedStream::Aes128CbcEncryptedStream() :
mBaseStream(),
mCryptor(std::shared_ptr<tc::crypto::Aes128CbcEncryptor>(new tc::crypto::Aes128CbcEncryptor()))
{
memset(mBaseIv.data(), 0, mBaseIv.size());
}
tc::crypto::Aes128CbcEncryptedStream::Aes128CbcEncryptedStream(const std::shared_ptr<tc::io::IStream>& stream, const key_t& key, const iv_t& iv) :
Aes128CbcEncryptedStream()
{
mBaseStream = stream;
// validate stream properties
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName, "stream is null.");
}
if (mBaseStream->canRead() == false)
{
throw tc::NotSupportedException(kClassName, "stream does not support reading.");
}
if (mBaseStream->canSeek() == false)
{
throw tc::NotSupportedException(kClassName, "stream does not support seeking.");
}
if ((mBaseStream->length() % sizeof(block_t)) != 0)
{
throw tc::NotSupportedException(kClassName, "stream does is not block aligned.");
}
// initialize cryptor
mCryptor->initialize(key.data(), key.size(), iv.data(), iv.size());
mBaseIv = iv;
}
bool tc::crypto::Aes128CbcEncryptedStream::canRead() const
{
return mBaseStream == nullptr ? false : mBaseStream->canRead();
}
bool tc::crypto::Aes128CbcEncryptedStream::canWrite() const
{
return false; // always false this is a read-only stream
}
bool tc::crypto::Aes128CbcEncryptedStream::canSeek() const
{
return mBaseStream == nullptr ? false : mBaseStream->canSeek();
}
int64_t tc::crypto::Aes128CbcEncryptedStream::length()
{
return mBaseStream == nullptr ? 0 : mBaseStream->length();
}
int64_t tc::crypto::Aes128CbcEncryptedStream::position()
{
return mBaseStream == nullptr ? 0 : mBaseStream->position();
}
size_t tc::crypto::Aes128CbcEncryptedStream::read(byte_t* ptr, size_t count)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::read()", "Failed to read from stream (stream is disposed)");
}
// track read_count
size_t data_read_count = 0;
// get predicted read count
count = tc::io::IOUtil::getReadableCount(this->length(), this->position(), count);
// if count is 0 just return
if (count == 0) return data_read_count;
// get current position
int64_t current_pos = mBaseStream->position();
if (current_pos < 0)
{
throw tc::InvalidOperationException(kClassName+"::read()", "Current stream position is negative.");
}
// determine begin & end offsets
int64_t begin_read_offset = current_pos;
int64_t end_read_offset = begin_read_offset + tc::io::IOUtil::castSizeToInt64(count);
int64_t begin_aligned_offset = begin_read_offset - tc::io::IOUtil::castSizeToInt64(offsetInBlock(begin_read_offset));
int64_t end_aligned_offset = end_read_offset - tc::io::IOUtil::castSizeToInt64(offsetInBlock(end_read_offset)) + tc::io::IOUtil::castSizeToInt64(offsetInBlock(end_read_offset) ? sizeof(block_t) : 0x0);
size_t block_num = lengthToBlockNum(end_aligned_offset - begin_aligned_offset);
bool read_partial_begin_block = false;
uint64_t partial_begin_block_index = offsetToBlockIndex(begin_read_offset);
size_t partial_begin_block_offset = 0;
size_t partial_begin_block_size = sizeof(block_t);
bool read_partial_end_block = false;
uint64_t partial_end_block_index = offsetToBlockIndex(end_read_offset);
size_t partial_end_block_offset = 0;
size_t partial_end_block_size = sizeof(block_t);
if (offsetInBlock(begin_read_offset) != 0)
{
read_partial_begin_block = true;
partial_begin_block_offset += offsetInBlock(begin_read_offset);
partial_begin_block_size -= partial_begin_block_offset;
}
if (offsetInBlock(end_read_offset) != 0)
{
if (partial_begin_block_index == partial_end_block_index)
{
read_partial_begin_block = true;
partial_begin_block_size -= (sizeof(block_t) - offsetInBlock(end_read_offset));
}
else
{
read_partial_end_block = true;
partial_end_block_size = offsetInBlock(end_read_offset);
}
}
size_t continuous_block_num = block_num - (size_t)read_partial_begin_block - (size_t)read_partial_end_block;
uint64_t continuous_begin_block_index = (continuous_block_num == 0) ? 0 : (offsetToBlockIndex(begin_aligned_offset) + (uint64_t)read_partial_begin_block);
/*
fmt::print("##############################################\n");
fmt::print("count: 0x{:x}\n", count);
fmt::print("begin_read_offset: 0x{:x}\n", begin_read_offset);
fmt::print("end_read_offset: 0x{:x}\n", end_read_offset);
fmt::print("begin_aligned_offset: 0x{:x}\n", begin_aligned_offset);
fmt::print("end_aligned_offset: 0x{:x}\n", end_aligned_offset);
fmt::print("block_num: 0x{:x}\n", block_num);
fmt::print("partial_begin:\n");
fmt::print(" read_block: {}\n", read_partial_begin_block);
fmt::print(" block_index: 0x{:x}\n", partial_begin_block_index);
fmt::print(" offset: 0x{:x}\n", partial_begin_block_offset);
fmt::print(" size: 0x{:x}\n", partial_begin_block_size);
fmt::print("partial_end:\n");
fmt::print(" read_block: {}\n", read_partial_end_block);
fmt::print(" block_index: 0x{:x}\n", partial_end_block_index);
fmt::print(" offset: 0x{:x}\n", partial_end_block_offset);
fmt::print(" size: 0x{:x}\n", partial_end_block_size);
fmt::print("continuous:\n");
fmt::print(" block_index: 0x{:x}\n", continuous_begin_block_index);
fmt::print(" block_num: 0x{:x}\n", continuous_block_num);
*/
if (block_num == 0)
{
tc::InvalidOperationException(kClassName+"::read()", "Invalid block number (0 blocks, would have returned before now if count==0)");
}
if (block_num < continuous_block_num)
{
tc::InvalidOperationException(kClassName+"::read()", "Invalid block number (underflow error)");
}
// allocate memory for partial block
tc::ByteData partial_block = tc::ByteData(sizeof(block_t));
// read un-aligned begin block
if (read_partial_begin_block)
{
// read iv
iv_t iv;
if (partial_begin_block_index == 0)
{
iv = mBaseIv;
}
else
{
this->seek(blockIndexToOffset(partial_begin_block_index-1), tc::io::SeekOrigin::Begin);
mBaseStream->read(iv.data(), iv.size());
}
mCryptor->update_iv(iv.data(), iv.size());
// read block
this->seek(blockIndexToOffset(partial_begin_block_index), tc::io::SeekOrigin::Begin);
mBaseStream->read(partial_block.data(), partial_block.size());
// decrypt block
mCryptor->decrypt(partial_block.data(), partial_block.data(), partial_block.size());
// copy out block carving
memcpy(ptr + data_read_count, partial_block.data() + partial_begin_block_offset, partial_begin_block_size);
// increment data read count
data_read_count += partial_begin_block_size;
}
// read continous blocks
if (continuous_block_num > 0)
{
// read iv
iv_t iv;
if (continuous_begin_block_index == 0)
{
iv = mBaseIv;
}
else
{
this->seek(blockIndexToOffset(continuous_begin_block_index-1), tc::io::SeekOrigin::Begin);
mBaseStream->read(iv.data(), iv.size());
}
mCryptor->update_iv(iv.data(), iv.size());
// read blocks
this->seek(blockIndexToOffset(continuous_begin_block_index), tc::io::SeekOrigin::Begin);
mBaseStream->read(ptr + data_read_count, continuous_block_num * sizeof(block_t));
// decrypt blocks
mCryptor->decrypt(ptr + data_read_count, ptr + data_read_count, continuous_block_num * sizeof(block_t));
// increment data read count
data_read_count += continuous_block_num * sizeof(block_t);
}
// read un-aligned end block
if (read_partial_end_block)
{
// read iv
iv_t iv;
if (partial_end_block_index == 0)
{
iv = mBaseIv;
}
else
{
this->seek(blockIndexToOffset(partial_end_block_index-1), tc::io::SeekOrigin::Begin);
mBaseStream->read(iv.data(), iv.size());
}
mCryptor->update_iv(iv.data(), iv.size());
// read block
this->seek(blockIndexToOffset(partial_end_block_index), tc::io::SeekOrigin::Begin);
mBaseStream->read(partial_block.data(), partial_block.size());
// decrypt block
mCryptor->decrypt(partial_block.data(), partial_block.data(), partial_block.size());
// copy out block carving
memcpy(ptr + data_read_count, partial_block.data() + partial_end_block_offset, partial_end_block_size);
// increment
data_read_count += partial_end_block_size;
}
// restore expected logical position
this->seek(begin_read_offset + tc::io::IOUtil::castSizeToInt64(data_read_count), tc::io::SeekOrigin::Begin);
// return data read count
return data_read_count;
}
size_t tc::crypto::Aes128CbcEncryptedStream::write(const byte_t* ptr, size_t count)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::write()", "Failed to set stream position (stream is disposed)");
}
throw tc::NotImplementedException(kClassName+"::write()", "write is not implemented for Aes128CbcEncryptedStream");
}
int64_t tc::crypto::Aes128CbcEncryptedStream::seek(int64_t offset, tc::io::SeekOrigin origin)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::seek()", "Failed to set stream position (stream is disposed)");
}
return mBaseStream->seek(offset, origin);
}
void tc::crypto::Aes128CbcEncryptedStream::setLength(int64_t length)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::setLength()", "Failed to set stream length (stream is disposed)");
}
throw tc::NotImplementedException(kClassName+"::setLength()", "setLength is not implemented for Aes128CbcEncryptedStream");
}
void tc::crypto::Aes128CbcEncryptedStream::flush()
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::seek()", "Failed to flush stream (stream is disposed)");
}
mBaseStream->flush();
}
void tc::crypto::Aes128CbcEncryptedStream::dispose()
{
if (mBaseStream.get() != nullptr)
{
// dispose base stream
mBaseStream->dispose();
// release ptr
mBaseStream.reset();
}
}
@@ -1,15 +0,0 @@
#include <tc/crypto/Aes128CbcEncryptor.h>
void tc::crypto::EncryptAes128Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes128CbcEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.encrypt(dst, src, size);
}
void tc::crypto::DecryptAes128Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes128CbcEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.decrypt(dst, src, size);
}
@@ -1,284 +0,0 @@
#include <tc/crypto/Aes128CtrEncryptedStream.h>
#include <tc/io/IOUtil.h>
#include <tc/io/StreamUtil.h>
/*
#include <fmt/core.h>
#include <tc/cli/FormatUtil.h>
*/
// inline utils
inline uint64_t castInt64ToUint64(int64_t val) { return val < 0 ? 0 : uint64_t(val); }
inline int64_t castUint64ToInt64(uint64_t val) { return (int64_t)std::min<uint64_t>(val, uint64_t(std::numeric_limits<int64_t>::max())); }
inline uint64_t offsetToBlockIndex(int64_t offset) { return castInt64ToUint64(offset / tc::io::IOUtil::castSizeToInt64(tc::crypto::Aes128CtrEncryptor::kBlockSize)); };
inline int64_t blockIndexToOffset(uint64_t block_index) { return castUint64ToInt64(block_index) * tc::io::IOUtil::castSizeToInt64(tc::crypto::Aes128CtrEncryptor::kBlockSize); };
inline size_t lengthToBlockNum(int64_t length) { return tc::io::IOUtil::castInt64ToSize(length / tc::io::IOUtil::castSizeToInt64(tc::crypto::Aes128CtrEncryptor::kBlockSize)); };
inline size_t offsetInBlock(int64_t offset) { return tc::io::IOUtil::castInt64ToSize(offset % tc::io::IOUtil::castSizeToInt64(tc::crypto::Aes128CtrEncryptor::kBlockSize)); };
const std::string tc::crypto::Aes128CtrEncryptedStream::kClassName = "tc::crypto::Aes128CtrEncryptedStream";
tc::crypto::Aes128CtrEncryptedStream::Aes128CtrEncryptedStream() :
mBaseStream(),
mCryptor(std::shared_ptr<tc::crypto::Aes128CtrEncryptor>(new tc::crypto::Aes128CtrEncryptor()))
{
}
tc::crypto::Aes128CtrEncryptedStream::Aes128CtrEncryptedStream(const std::shared_ptr<tc::io::IStream>& stream, const key_t& key, const counter_t& counter) :
Aes128CtrEncryptedStream()
{
mBaseStream = stream;
// validate stream properties
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName, "stream is null.");
}
if (mBaseStream->canRead() == false)
{
throw tc::NotSupportedException(kClassName, "stream does not support reading.");
}
if (mBaseStream->canSeek() == false)
{
throw tc::NotSupportedException(kClassName, "stream does not support seeking.");
}
// initialize cryptor
mCryptor->initialize(key.data(), key.size(), counter.data(), counter.size());
}
bool tc::crypto::Aes128CtrEncryptedStream::canRead() const
{
return mBaseStream == nullptr ? false : mBaseStream->canRead();
}
bool tc::crypto::Aes128CtrEncryptedStream::canWrite() const
{
return false; // always false this is a read-only stream
}
bool tc::crypto::Aes128CtrEncryptedStream::canSeek() const
{
return mBaseStream == nullptr ? false : mBaseStream->canSeek();
}
int64_t tc::crypto::Aes128CtrEncryptedStream::length()
{
return mBaseStream == nullptr ? 0 : mBaseStream->length();
}
int64_t tc::crypto::Aes128CtrEncryptedStream::position()
{
return mBaseStream == nullptr ? 0 : mBaseStream->position();
}
size_t tc::crypto::Aes128CtrEncryptedStream::read(byte_t* ptr, size_t count)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::read()", "Failed to read from stream (stream is disposed)");
}
// track read_count
size_t data_read_count = 0;
// get predicted read count
count = tc::io::IOUtil::getReadableCount(this->length(), this->position(), count);
// if count is 0 just return
if (count == 0) return data_read_count;
// get current position
int64_t current_pos = mBaseStream->position();
if (current_pos < 0)
{
throw tc::InvalidOperationException(kClassName+"::read()", "Current stream position is negative.");
}
// determine begin & end offsets
int64_t begin_read_offset = current_pos;
int64_t end_read_offset = begin_read_offset + tc::io::IOUtil::castSizeToInt64(count);
int64_t begin_aligned_offset = begin_read_offset - tc::io::IOUtil::castSizeToInt64(offsetInBlock(begin_read_offset));
int64_t end_aligned_offset = end_read_offset - tc::io::IOUtil::castSizeToInt64(offsetInBlock(end_read_offset)) + tc::io::IOUtil::castSizeToInt64(offsetInBlock(end_read_offset) ? sizeof(block_t) : 0x0);
size_t block_num = lengthToBlockNum(end_aligned_offset - begin_aligned_offset);
bool read_partial_begin_block = false;
uint64_t partial_begin_block_index = offsetToBlockIndex(begin_read_offset);
size_t partial_begin_block_offset = 0;
size_t partial_begin_block_size = sizeof(block_t);
bool read_partial_end_block = false;
uint64_t partial_end_block_index = offsetToBlockIndex(end_read_offset);
size_t partial_end_block_offset = 0;
size_t partial_end_block_size = sizeof(block_t);
if (offsetInBlock(begin_read_offset) != 0)
{
read_partial_begin_block = true;
partial_begin_block_offset += offsetInBlock(begin_read_offset);
partial_begin_block_size -= partial_begin_block_offset;
}
if (offsetInBlock(end_read_offset) != 0)
{
if (partial_begin_block_index == partial_end_block_index)
{
read_partial_begin_block = true;
partial_begin_block_size -= (sizeof(block_t) - offsetInBlock(end_read_offset));
}
else
{
read_partial_end_block = true;
partial_end_block_size = offsetInBlock(end_read_offset);
}
}
size_t continuous_block_num = block_num - (size_t)read_partial_begin_block - (size_t)read_partial_end_block;
uint64_t continuous_begin_block_index = (continuous_block_num == 0) ? 0 : (offsetToBlockIndex(begin_aligned_offset) + (uint64_t)read_partial_begin_block);
/*
fmt::print("##############################################\n");
fmt::print("count: 0x{:x}\n", count);
fmt::print("begin_read_offset: 0x{:x}\n", begin_read_offset);
fmt::print("end_read_offset: 0x{:x}\n", end_read_offset);
fmt::print("begin_aligned_offset: 0x{:x}\n", begin_aligned_offset);
fmt::print("end_aligned_offset: 0x{:x}\n", end_aligned_offset);
fmt::print("block_num: 0x{:x}\n", block_num);
fmt::print("partial_begin:\n");
fmt::print(" read_block: {}\n", read_partial_begin_block);
fmt::print(" block_index: 0x{:x}\n", partial_begin_block_index);
fmt::print(" offset: 0x{:x}\n", partial_begin_block_offset);
fmt::print(" size: 0x{:x}\n", partial_begin_block_size);
fmt::print("partial_end:\n");
fmt::print(" read_block: {}\n", read_partial_end_block);
fmt::print(" block_index: 0x{:x}\n", partial_end_block_index);
fmt::print(" offset: 0x{:x}\n", partial_end_block_offset);
fmt::print(" size: 0x{:x}\n", partial_end_block_size);
fmt::print("continuous:\n");
fmt::print(" block_index: 0x{:x}\n", continuous_begin_block_index);
fmt::print(" block_num: 0x{:x}\n", continuous_block_num);
*/
if (block_num == 0)
{
tc::InvalidOperationException(kClassName+"::read()", "Invalid block number (0 blocks, would have returned before now if count==0)");
}
if (block_num < continuous_block_num)
{
tc::InvalidOperationException(kClassName+"::read()", "Invalid block number (underflow error)");
}
// allocate memory for partial block
tc::ByteData partial_block = tc::ByteData(sizeof(block_t));
// read un-aligned begin block
if (read_partial_begin_block)
{
// read block
this->seek(blockIndexToOffset(partial_begin_block_index), tc::io::SeekOrigin::Begin);
mBaseStream->read(partial_block.data(), partial_block.size());
// decrypt block
mCryptor->decrypt(partial_block.data(), partial_block.data(), partial_block.size(), partial_begin_block_index);
// copy out block carving
memcpy(ptr + data_read_count, partial_block.data() + partial_begin_block_offset, partial_begin_block_size);
// increment data read count
data_read_count += partial_begin_block_size;
}
// read continous blocks
if (continuous_block_num > 0)
{
// read blocks
this->seek(blockIndexToOffset(continuous_begin_block_index), tc::io::SeekOrigin::Begin);
mBaseStream->read(ptr + data_read_count, continuous_block_num * sizeof(block_t));
// decrypt blocks
mCryptor->decrypt(ptr + data_read_count, ptr + data_read_count, continuous_block_num * sizeof(block_t), continuous_begin_block_index);
// increment data read count
data_read_count += continuous_block_num * sizeof(block_t);
}
// read un-aligned end block
if (read_partial_end_block)
{
// read block
this->seek(blockIndexToOffset(partial_end_block_index), tc::io::SeekOrigin::Begin);
mBaseStream->read(partial_block.data(), partial_block.size());
// decrypt block
mCryptor->decrypt(partial_block.data(), partial_block.data(), partial_block.size(), partial_end_block_index);
// copy out block carving
memcpy(ptr + data_read_count, partial_block.data() + partial_end_block_offset, partial_end_block_size);
// increment
data_read_count += partial_end_block_size;
}
// restore expected logical position
this->seek(begin_read_offset + tc::io::IOUtil::castSizeToInt64(data_read_count), tc::io::SeekOrigin::Begin);
// return data read count
return data_read_count;
}
size_t tc::crypto::Aes128CtrEncryptedStream::write(const byte_t* ptr, size_t count)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::write()", "Failed to set stream position (stream is disposed)");
}
throw tc::NotImplementedException(kClassName+"::write()", "write is not implemented for Aes128CtrEncryptedStream");
}
int64_t tc::crypto::Aes128CtrEncryptedStream::seek(int64_t offset, tc::io::SeekOrigin origin)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::seek()", "Failed to set stream position (stream is disposed)");
}
return mBaseStream->seek(offset, origin);
}
void tc::crypto::Aes128CtrEncryptedStream::setLength(int64_t length)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::setLength()", "Failed to set stream length (stream is disposed)");
}
throw tc::NotImplementedException(kClassName+"::setLength()", "setLength is not implemented for Aes128CtrEncryptedStream");
}
void tc::crypto::Aes128CtrEncryptedStream::flush()
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::seek()", "Failed to flush stream (stream is disposed)");
}
mBaseStream->flush();
}
void tc::crypto::Aes128CtrEncryptedStream::dispose()
{
if (mBaseStream != nullptr)
{
// dispose base stream
mBaseStream->dispose();
// release ptr
mBaseStream.reset();
}
if (mCryptor != nullptr)
mCryptor.reset();
}
@@ -1,24 +0,0 @@
#include <tc/crypto/Aes128CtrEncryptor.h>
void tc::crypto::EncryptAes128Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes128CtrEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.encrypt(dst, src, size, block_number);
}
void tc::crypto::DecryptAes128Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes128CtrEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.decrypt(dst, src, size, block_number);
}
void tc::crypto::IncrementCounterAes128Ctr(byte_t* counter, uint64_t incr)
{
if (counter == nullptr)
{
throw tc::ArgumentOutOfRangeException("counter was null.");
}
tc::crypto::detail::incr_counter<16>(counter, incr);
}
@@ -1,15 +0,0 @@
#include <tc/crypto/Aes128EcbEncryptor.h>
void tc::crypto::EncryptAes128Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size)
{
tc::crypto::Aes128EcbEncryptor crypt;
crypt.initialize(key, key_size);
crypt.encrypt(dst, src, size);
}
void tc::crypto::DecryptAes128Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size)
{
tc::crypto::Aes128EcbEncryptor crypt;
crypt.initialize(key, key_size);
crypt.decrypt(dst, src, size);
}
@@ -1,15 +0,0 @@
#include <tc/crypto/Aes128XtsEncryptor.h>
void tc::crypto::EncryptAes128Xts(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number, const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order)
{
tc::crypto::Aes128XtsEncryptor crypt;
crypt.initialize(key1, key1_size, key2, key2_size, sector_size, tweak_word_order);
crypt.encrypt(dst, src, size, sector_number);
}
void tc::crypto::DecryptAes128Xts(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number, const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order)
{
tc::crypto::Aes128XtsEncryptor crypt;
crypt.initialize(key1, key1_size, key2, key2_size, sector_size, tweak_word_order);
crypt.decrypt(dst, src, size, sector_number);
}
@@ -1,15 +0,0 @@
#include <tc/crypto/Aes192CbcEncryptor.h>
void tc::crypto::EncryptAes192Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes192CbcEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.encrypt(dst, src, size);
}
void tc::crypto::DecryptAes192Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes192CbcEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.decrypt(dst, src, size);
}
@@ -1,24 +0,0 @@
#include <tc/crypto/Aes192CtrEncryptor.h>
void tc::crypto::EncryptAes192Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes192CtrEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.encrypt(dst, src, size, block_number);
}
void tc::crypto::DecryptAes192Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes192CtrEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.decrypt(dst, src, size, block_number);
}
void tc::crypto::IncrementCounterAes192Ctr(byte_t* counter, uint64_t incr)
{
if (counter == nullptr)
{
throw tc::ArgumentOutOfRangeException("counter was null.");
}
tc::crypto::detail::incr_counter<16>(counter, incr);
}
@@ -1,15 +0,0 @@
#include <tc/crypto/Aes192EcbEncryptor.h>
void tc::crypto::EncryptAes192Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size)
{
tc::crypto::Aes192EcbEncryptor crypt;
crypt.initialize(key, key_size);
crypt.encrypt(dst, src, size);
}
void tc::crypto::DecryptAes192Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size)
{
tc::crypto::Aes192EcbEncryptor crypt;
crypt.initialize(key, key_size);
crypt.decrypt(dst, src, size);
}
@@ -1,15 +0,0 @@
#include <tc/crypto/Aes256CbcEncryptor.h>
void tc::crypto::EncryptAes256Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes256CbcEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.encrypt(dst, src, size);
}
void tc::crypto::DecryptAes256Cbc(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes256CbcEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.decrypt(dst, src, size);
}
@@ -1,24 +0,0 @@
#include <tc/crypto/Aes256CtrEncryptor.h>
void tc::crypto::EncryptAes256Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes256CtrEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.encrypt(dst, src, size, block_number);
}
void tc::crypto::DecryptAes256Ctr(byte_t* dst, const byte_t* src, size_t size, uint64_t block_number, const byte_t* key, size_t key_size, const byte_t* iv, size_t iv_size)
{
tc::crypto::Aes256CtrEncryptor crypt;
crypt.initialize(key, key_size, iv, iv_size);
crypt.decrypt(dst, src, size, block_number);
}
void tc::crypto::IncrementCounterAes256Ctr(byte_t* counter, uint64_t incr)
{
if (counter == nullptr)
{
throw tc::ArgumentOutOfRangeException("counter was null.");
}
tc::crypto::detail::incr_counter<16>(counter, incr);
}
@@ -1,15 +0,0 @@
#include <tc/crypto/Aes256EcbEncryptor.h>
void tc::crypto::EncryptAes256Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size)
{
tc::crypto::Aes256EcbEncryptor crypt;
crypt.initialize(key, key_size);
crypt.encrypt(dst, src, size);
}
void tc::crypto::DecryptAes256Ecb(byte_t* dst, const byte_t* src, size_t size, const byte_t* key, size_t key_size)
{
tc::crypto::Aes256EcbEncryptor crypt;
crypt.initialize(key, key_size);
crypt.decrypt(dst, src, size);
}
@@ -1,15 +0,0 @@
#include <tc/crypto/Aes256XtsEncryptor.h>
void tc::crypto::EncryptAes256Xts(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number, const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order)
{
tc::crypto::Aes256XtsEncryptor crypt;
crypt.initialize(key1, key1_size, key2, key2_size, sector_size, tweak_word_order);
crypt.encrypt(dst, src, size, sector_number);
}
void tc::crypto::DecryptAes256Xts(byte_t* dst, const byte_t* src, size_t size, uint64_t sector_number, const byte_t* key1, size_t key1_size, const byte_t* key2, size_t key2_size, size_t sector_size, bool tweak_word_order)
{
tc::crypto::Aes256XtsEncryptor crypt;
crypt.initialize(key1, key1_size, key2, key2_size, sector_size, tweak_word_order);
crypt.decrypt(dst, src, size, sector_number);
}
@@ -1,9 +0,0 @@
#include <tc/crypto/HmacMd5Generator.h>
void tc::crypto::GenerateHmacMd5Mac(byte_t* mac, const byte_t* data, size_t data_size, const byte_t* key, size_t key_size)
{
tc::crypto::HmacMd5Generator impl;
impl.initialize(key, key_size);
impl.update(data, data_size);
impl.getMac(mac);
}
@@ -1,9 +0,0 @@
#include <tc/crypto/HmacSha1Generator.h>
void tc::crypto::GenerateHmacSha1Mac(byte_t* mac, const byte_t* data, size_t data_size, const byte_t* key, size_t key_size)
{
tc::crypto::HmacSha1Generator impl;
impl.initialize(key, key_size);
impl.update(data, data_size);
impl.getMac(mac);
}
@@ -1,9 +0,0 @@
#include <tc/crypto/HmacSha256Generator.h>
void tc::crypto::GenerateHmacSha256Mac(byte_t* mac, const byte_t* data, size_t data_size, const byte_t* key, size_t key_size)
{
tc::crypto::HmacSha256Generator impl;
impl.initialize(key, key_size);
impl.update(data, data_size);
impl.getMac(mac);
}
@@ -1,9 +0,0 @@
#include <tc/crypto/HmacSha512Generator.h>
void tc::crypto::GenerateHmacSha512Mac(byte_t* mac, const byte_t* data, size_t data_size, const byte_t* key, size_t key_size)
{
tc::crypto::HmacSha512Generator impl;
impl.initialize(key, key_size);
impl.update(data, data_size);
impl.getMac(mac);
}
@@ -1,11 +0,0 @@
#include <tc/crypto/Md5Generator.h>
const std::array<byte_t, tc::crypto::Md5Generator::kAsn1OidDataSize> tc::crypto::Md5Generator::kAsn1OidData = {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10};
void tc::crypto::GenerateMd5Hash(byte_t* hash, const byte_t* data, size_t data_size)
{
tc::crypto::Md5Generator impl;
impl.initialize();
impl.update(data, data_size);
impl.getHash(hash);
}
@@ -1,8 +0,0 @@
#include <tc/crypto/Pbkdf1Md5KeyDeriver.h>
void tc::crypto::DeriveKeyPbkdf1Md5(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
{
tc::crypto::Pbkdf1Md5KeyDeriver impl;
impl.initialize(password, password_size, salt, salt_size, n_rounds);
impl.getBytes(key, key_size);
}
@@ -1,8 +0,0 @@
#include <tc/crypto/Pbkdf1Sha1KeyDeriver.h>
void tc::crypto::DeriveKeyPbkdf1Sha1(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
{
tc::crypto::Pbkdf1Sha1KeyDeriver impl;
impl.initialize(password, password_size, salt, salt_size, n_rounds);
impl.getBytes(key, key_size);
}
@@ -1,8 +0,0 @@
#include <tc/crypto/Pbkdf2Sha1KeyDeriver.h>
void tc::crypto::DeriveKeyPbkdf2Sha1(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
{
tc::crypto::Pbkdf2Sha1KeyDeriver impl;
impl.initialize(password, password_size, salt, salt_size, n_rounds);
impl.getBytes(key, key_size);
}
@@ -1,8 +0,0 @@
#include <tc/crypto/Pbkdf2Sha256KeyDeriver.h>
void tc::crypto::DeriveKeyPbkdf2Sha256(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
{
tc::crypto::Pbkdf2Sha256KeyDeriver impl;
impl.initialize(password, password_size, salt, salt_size, n_rounds);
impl.getBytes(key, key_size);
}
@@ -1,8 +0,0 @@
#include <tc/crypto/Pbkdf2Sha512KeyDeriver.h>
void tc::crypto::DeriveKeyPbkdf2Sha512(byte_t* key, size_t key_size, const byte_t* password, size_t password_size, const byte_t* salt, size_t salt_size, size_t n_rounds)
{
tc::crypto::Pbkdf2Sha512KeyDeriver impl;
impl.initialize(password, password_size, salt, salt_size, n_rounds);
impl.getBytes(key, key_size);
}
@@ -1,7 +0,0 @@
#include <tc/crypto/PseudoRandomByteGenerator.h>
void tc::crypto::GeneratePseudoRandomBytes(byte_t* data, size_t data_size)
{
tc::crypto::PseudoRandomByteGenerator impl;
impl.getBytes(data, data_size);
}
@@ -1,29 +0,0 @@
#include <tc/crypto/RsaKey.h>
tc::crypto::RsaPublicKey::RsaPublicKey(const byte_t* modulus, size_t modulus_size)
{
static const byte_t kPublicExponent[3] = { 0x01, 0x00, 0x01 };
if (modulus != nullptr && modulus_size != 0)
{
this->n = tc::ByteData(modulus, modulus_size);
this->e = tc::ByteData(kPublicExponent, sizeof(kPublicExponent));
}
}
tc::crypto::RsaPrivateKey::RsaPrivateKey(const byte_t* modulus, size_t modulus_size, const byte_t* private_exponent, size_t private_exponent_size)
{
static const byte_t kPublicExponent[3] = { 0x01, 0x00, 0x01 };
if (modulus != nullptr && modulus_size != 0 && private_exponent != nullptr && private_exponent_size != 0)
{
this->n = tc::ByteData(modulus, modulus_size);
this->d = tc::ByteData(private_exponent, private_exponent_size);
this->e = tc::ByteData(kPublicExponent, sizeof(kPublicExponent));
}
}
tc::crypto::RsaKey tc::crypto::RsaPrivateKey::getPublicKey()
{
return RsaPublicKey(this->n.data(), this->n.size());
}
@@ -1,7 +0,0 @@
#include <tc/crypto/RsaKeyGenerator.h>
void tc::crypto::GenerateRsaKey(RsaKey& key, size_t key_bit_size)
{
tc::crypto::RsaKeyGenerator impl;
impl.generateKey(key, key_bit_size);
}
@@ -1,43 +0,0 @@
#include <tc/crypto/RsaOaepSha256Encryptor.h>
bool tc::crypto::EncryptRsa1024OaepSha256(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa1024OaepSha256Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.encrypt(block, message, message_size);
}
bool tc::crypto::DecryptRsa1024OaepSha256(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa1024OaepSha256Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.decrypt(message, message_size, message_capacity, block);
}
bool tc::crypto::EncryptRsa2048OaepSha256(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa2048OaepSha256Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.encrypt(block, message, message_size);
}
bool tc::crypto::DecryptRsa2048OaepSha256(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa2048OaepSha256Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.decrypt(message, message_size, message_capacity, block);
}
bool tc::crypto::EncryptRsa4096OaepSha256(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa4096OaepSha256Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.encrypt(block, message, message_size);
}
bool tc::crypto::DecryptRsa4096OaepSha256(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa4096OaepSha256Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.decrypt(message, message_size, message_capacity, block);
}
@@ -1,29 +0,0 @@
#include <tc/crypto/RsaOaepSha512Encryptor.h>
bool tc::crypto::EncryptRsa2048OaepSha512(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa2048OaepSha512Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.encrypt(block, message, message_size);
}
bool tc::crypto::DecryptRsa2048OaepSha512(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa2048OaepSha512Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.decrypt(message, message_size, message_capacity, block);
}
bool tc::crypto::EncryptRsa4096OaepSha512(byte_t* block, const byte_t* message, size_t message_size, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa4096OaepSha512Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.encrypt(block, message, message_size);
}
bool tc::crypto::DecryptRsa4096OaepSha512(byte_t* message, size_t& message_size, size_t message_capacity, const byte_t* block, const RsaKey& key, const byte_t* label, size_t label_size, bool isLabelDigested)
{
tc::crypto::Rsa4096OaepSha512Encryptor impl;
impl.initialize(key, label, label_size, isLabelDigested);
return impl.decrypt(message, message_size, message_capacity, block);
}
@@ -1,43 +0,0 @@
#include <tc/crypto/RsaPkcs1Md5Signer.h>
bool tc::crypto::SignRsa1024Pkcs1Md5(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024Pkcs1Md5Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa1024Pkcs1Md5(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024Pkcs1Md5Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa2048Pkcs1Md5(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048Pkcs1Md5Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa2048Pkcs1Md5(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048Pkcs1Md5Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa4096Pkcs1Md5(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096Pkcs1Md5Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa4096Pkcs1Md5(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096Pkcs1Md5Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
@@ -1,43 +0,0 @@
#include <tc/crypto/RsaPkcs1Sha1Signer.h>
bool tc::crypto::SignRsa1024Pkcs1Sha1(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024Pkcs1Sha1Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa1024Pkcs1Sha1(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024Pkcs1Sha1Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa2048Pkcs1Sha1(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048Pkcs1Sha1Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa2048Pkcs1Sha1(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048Pkcs1Sha1Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa4096Pkcs1Sha1(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096Pkcs1Sha1Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa4096Pkcs1Sha1(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096Pkcs1Sha1Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
@@ -1,43 +0,0 @@
#include <tc/crypto/RsaPkcs1Sha256Signer.h>
bool tc::crypto::SignRsa1024Pkcs1Sha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024Pkcs1Sha256Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa1024Pkcs1Sha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024Pkcs1Sha256Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa2048Pkcs1Sha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048Pkcs1Sha256Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa2048Pkcs1Sha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048Pkcs1Sha256Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa4096Pkcs1Sha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096Pkcs1Sha256Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa4096Pkcs1Sha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096Pkcs1Sha256Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
@@ -1,43 +0,0 @@
#include <tc/crypto/RsaPkcs1Sha512Signer.h>
bool tc::crypto::SignRsa1024Pkcs1Sha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024Pkcs1Sha512Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa1024Pkcs1Sha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024Pkcs1Sha512Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa2048Pkcs1Sha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048Pkcs1Sha512Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa2048Pkcs1Sha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048Pkcs1Sha512Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa4096Pkcs1Sha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096Pkcs1Sha512Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa4096Pkcs1Sha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096Pkcs1Sha512Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
@@ -1,43 +0,0 @@
#include <tc/crypto/RsaPssSha256Signer.h>
bool tc::crypto::SignRsa1024PssSha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024PssSha256Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa1024PssSha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024PssSha256Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa2048PssSha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048PssSha256Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa2048PssSha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048PssSha256Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa4096PssSha256(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096PssSha256Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa4096PssSha256(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096PssSha256Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
@@ -1,43 +0,0 @@
#include <tc/crypto/RsaPssSha512Signer.h>
bool tc::crypto::SignRsa1024PssSha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024PssSha512Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa1024PssSha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa1024PssSha512Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa2048PssSha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048PssSha512Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa2048PssSha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa2048PssSha512Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
bool tc::crypto::SignRsa4096PssSha512(byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096PssSha512Signer impl;
impl.initialize(key);
return impl.sign(signature, message_digest);
}
bool tc::crypto::VerifyRsa4096PssSha512(const byte_t* signature, const byte_t* message_digest, const RsaKey& key)
{
tc::crypto::Rsa4096PssSha512Signer impl;
impl.initialize(key);
return impl.verify(signature, message_digest);
}
@@ -1,12 +0,0 @@
#include <tc/crypto/Sha1Generator.h>
const std::array<byte_t, tc::crypto::Sha1Generator::kAsn1OidDataSize> tc::crypto::Sha1Generator::kAsn1OidData = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
void tc::crypto::GenerateSha1Hash(byte_t* hash, const byte_t* data, size_t data_size)
{
tc::crypto::Sha1Generator impl;
impl.initialize();
impl.update(data, data_size);
impl.getHash(hash);
}
@@ -1,11 +0,0 @@
#include <tc/crypto/Sha256Generator.h>
const std::array<byte_t, tc::crypto::Sha256Generator::kAsn1OidDataSize> tc::crypto::Sha256Generator::kAsn1OidData = {0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
void tc::crypto::GenerateSha256Hash(byte_t* hash, const byte_t* data, size_t data_size)
{
tc::crypto::Sha256Generator impl;
impl.initialize();
impl.update(data, data_size);
impl.getHash(hash);
}
@@ -1,11 +0,0 @@
#include <tc/crypto/Sha512Generator.h>
const std::array<byte_t, tc::crypto::Sha512Generator::kAsn1OidDataSize> tc::crypto::Sha512Generator::kAsn1OidData = {0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
void tc::crypto::GenerateSha512Hash(byte_t* hash, const byte_t* data, size_t data_size)
{
tc::crypto::Sha512Generator impl;
impl.initialize();
impl.update(data, data_size);
impl.getHash(hash);
}
@@ -1,51 +0,0 @@
#include <tc/crypto/detail/AesImpl.h>
#include <mbedtls/aes.h>
struct tc::crypto::detail::AesImpl::ImplCtx
{
mbedtls_aes_context mEncContext;
mbedtls_aes_context mDecContext;
};
tc::crypto::detail::AesImpl::AesImpl() :
mState(State::None),
mImplCtx(new ImplCtx())
{
mbedtls_aes_init(&(mImplCtx->mEncContext));
mbedtls_aes_init(&(mImplCtx->mDecContext));
}
tc::crypto::detail::AesImpl::~AesImpl()
{
mbedtls_aes_free(&(mImplCtx->mEncContext));
mbedtls_aes_free(&(mImplCtx->mDecContext));
}
void tc::crypto::detail::AesImpl::initialize(const byte_t* key, size_t key_size)
{
if (key == nullptr) { throw tc::ArgumentNullException("AesImpl::initialize()", "key was null."); }
if (key_size != 16 && key_size != 24 && key_size != 32) { throw tc::ArgumentOutOfRangeException("AesImpl::initialize()", "key_size did not equal 16, 24 or 32."); }
mbedtls_aes_setkey_enc(&(mImplCtx->mEncContext), key, uint32_t(key_size) * 8);
mbedtls_aes_setkey_dec(&(mImplCtx->mDecContext), key, uint32_t(key_size) * 8);
mState = State::Initialized;
}
void tc::crypto::detail::AesImpl::encrypt(byte_t* dst, const byte_t* src)
{
if (mState != State::Initialized) { return; }
if (dst == nullptr) { throw tc::ArgumentNullException("AesImpl::encrypt()", "dst was null."); }
if (src == nullptr) { throw tc::ArgumentNullException("AesImpl::encrypt()", "src was null."); }
mbedtls_aes_crypt_ecb(&(mImplCtx->mEncContext), MBEDTLS_AES_ENCRYPT, src, dst);
}
void tc::crypto::detail::AesImpl::decrypt(byte_t* dst, const byte_t* src)
{
if (mState != State::Initialized) { return; }
if (dst == nullptr) { throw tc::ArgumentNullException("AesImpl::decrypt()", "dst was null."); }
if (src == nullptr) { throw tc::ArgumentNullException("AesImpl::decrypt()", "src was null."); }
mbedtls_aes_crypt_ecb(&(mImplCtx->mDecContext), MBEDTLS_AES_DECRYPT, src, dst);
}
@@ -1,44 +0,0 @@
#include <tc/crypto/detail/Md5Impl.h>
#include <mbedtls/md.h>
struct tc::crypto::detail::Md5Impl::ImplCtx
{
mbedtls_md_context_t mMdContext;
};
tc::crypto::detail::Md5Impl::Md5Impl() :
mState(State::None),
mImplCtx(new ImplCtx())
{
mbedtls_md_init(&(mImplCtx->mMdContext));
mbedtls_md_setup(&(mImplCtx->mMdContext), mbedtls_md_info_from_type(MBEDTLS_MD_MD5), 0);
}
tc::crypto::detail::Md5Impl::~Md5Impl()
{
mbedtls_md_free(&(mImplCtx->mMdContext));
}
void tc::crypto::detail::Md5Impl::initialize()
{
mbedtls_md_starts(&(mImplCtx->mMdContext));
mState = State::Initialized;
}
void tc::crypto::detail::Md5Impl::update(const byte_t* src, size_t src_size)
{
mbedtls_md_update(&(mImplCtx->mMdContext), src, src_size);
}
void tc::crypto::detail::Md5Impl::getHash(byte_t* hash)
{
if (mState == State::Initialized)
{
mbedtls_md_finish(&(mImplCtx->mMdContext), mHash.data());
mState = State::Done;
}
if (mState == State::Done)
{
memcpy(hash, mHash.data(), mHash.size());
}
}
@@ -1,50 +0,0 @@
#include <tc/crypto/detail/PrbgImpl.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
const std::string tc::crypto::detail::PrbgImpl::kClassName = "tc::crypto::detail::PrbgImpl";
struct tc::crypto::detail::PrbgImpl::ImplCtx
{
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_context entropy;
};
tc::crypto::detail::PrbgImpl::PrbgImpl() :
mImplCtx(new ImplCtx())
{
mbedtls_ctr_drbg_init(&(mImplCtx->ctr_drbg));
mbedtls_entropy_init(&(mImplCtx->entropy));
int ret = mbedtls_ctr_drbg_seed(&(mImplCtx->ctr_drbg), mbedtls_entropy_func, &(mImplCtx->entropy), (const unsigned char *)kClassName.c_str(), kClassName.size());
switch (ret)
{
case (0):
break;
case (MBEDTLS_ERR_ENTROPY_SOURCE_FAILED):
throw tc::crypto::CryptoException(kClassName, "Entropy source failed");
default:
throw tc::crypto::CryptoException(kClassName, "An unexpected error occurred");
}
}
tc::crypto::detail::PrbgImpl::~PrbgImpl()
{
mbedtls_ctr_drbg_free(&(mImplCtx->ctr_drbg));
mbedtls_entropy_free(&(mImplCtx->entropy));
}
void tc::crypto::detail::PrbgImpl::getBytes(byte_t* data, size_t data_size)
{
int ret = mbedtls_ctr_drbg_random(&(mImplCtx->ctr_drbg), data, data_size);
switch (ret)
{
case (0):
break;
case (MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG):
throw tc::crypto::CryptoException(kClassName, "Request too big");
case (MBEDTLS_ERR_ENTROPY_SOURCE_FAILED):
throw tc::crypto::CryptoException(kClassName, "Entropy source failed");
default:
throw tc::crypto::CryptoException(kClassName, "An unexpected error occurred");
}
}
@@ -1,140 +0,0 @@
#include <tc/crypto/detail/RsaImpl.h>
#include <mbedtls/rsa.h>
struct tc::crypto::detail::RsaImpl::ImplCtx
{
mbedtls_rsa_context mContext;
};
tc::crypto::detail::RsaImpl::RsaImpl() :
mState(State::None),
mImplCtx(new ImplCtx())
{
mbedtls_rsa_init(&(mImplCtx->mContext), MBEDTLS_RSA_PKCS_V15, 0);
}
tc::crypto::detail::RsaImpl::~RsaImpl()
{
mbedtls_rsa_free(&(mImplCtx->mContext));
}
void tc::crypto::detail::RsaImpl::initialize(size_t key_bit_size, const byte_t* n, size_t n_size, const byte_t* p, size_t p_size, const byte_t* q, size_t q_size, const byte_t* d, size_t d_size, const byte_t* e, size_t e_size)
{
if ((key_bit_size % 8) != 0) { throw tc::ArgumentOutOfRangeException("RsaImpl::initialize()", "key_bit_size was not a multiple of 8 bits."); }
if (n == nullptr && n_size != 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "n was null when n_size was not 0."); }
if (p == nullptr && p_size != 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "p was null when p_size was not 0."); }
if (q == nullptr && q_size != 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "q was null when q_size was not 0."); }
if (d == nullptr && d_size != 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "d was null when d_size was not 0."); }
if (e == nullptr && e_size != 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "e was null when e_size was not 0."); }
if (n != nullptr && n_size == 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "n was not null but n_size was 0."); }
if (p != nullptr && p_size == 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "p was not null but p_size was 0."); }
if (q != nullptr && q_size == 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "q was not null but q_size was 0."); }
if (d != nullptr && d_size == 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "d was not null but d_size was 0."); }
if (e != nullptr && e_size == 0) { throw tc::ArgumentNullException("RsaImpl::initialize()", "e was not null but e_size was 0."); }
if (n_size > 0 && n_size != (key_bit_size/8)) { throw tc::ArgumentNullException("RsaImpl::initialize()", "n_size was non-zero but not expected size."); }
if (p_size > 0 && p_size != (key_bit_size/8)/2) { throw tc::ArgumentNullException("RsaImpl::initialize()", "p_size was non-zero but not expected size."); }
if (q_size > 0 && q_size != (key_bit_size/8)/2) { throw tc::ArgumentNullException("RsaImpl::initialize()", "q_size was non-zero but not expected size."); }
if (d_size > 0 && d_size != (key_bit_size/8)) { throw tc::ArgumentNullException("RsaImpl::initialize()", "d_size was non-zero but not expected size."); }
if (e_size > 0 && e_size != 3 && e_size != 4) { throw tc::ArgumentNullException("RsaImpl::initialize()", "e_size was non-zero but not expected size."); }
mImplCtx->mContext.len = key_bit_size / 8;
int ret = mbedtls_rsa_import_raw(&(mImplCtx->mContext), n, n_size, p, p_size, q, q_size, d, d_size, e, e_size);
// TODO: Confirm these error codes
if (ret != 0)
{
if (ret < MBEDTLS_ERR_RSA_BAD_INPUT_DATA) { throw tc::crypto::CryptoException("RsaImpl::initialize()", "Bad input parameters to function."); }
else { throw tc::crypto::CryptoException("RsaImpl::initialize()", "An unexpected error occurred."); }
}
mState = State::Initialized;
}
void tc::crypto::detail::RsaImpl::publicTransform(byte_t* dst, const byte_t* src)
{
if (mState != State::Initialized) { return; }
if (dst == nullptr) { throw tc::ArgumentNullException("RsaImpl::publicTransform()", "dst was null."); }
if (src == nullptr) { throw tc::ArgumentNullException("RsaImpl::publicTransform()", "src was null."); }
int ret = mbedtls_rsa_public(&(mImplCtx->mContext), src, dst);
switch (ret)
{
case (0):
break;
case (MBEDTLS_ERR_RSA_BAD_INPUT_DATA):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "Bad input parameters to function.");
break;
case (MBEDTLS_ERR_RSA_INVALID_PADDING):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "Input data contains invalid padding and is rejected.");
break;
case (MBEDTLS_ERR_RSA_KEY_GEN_FAILED):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "Something failed during generation of a key.");
break;
case (MBEDTLS_ERR_RSA_KEY_CHECK_FAILED):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "Key failed to pass the validity check of the library.");
break;
case (MBEDTLS_ERR_RSA_PUBLIC_FAILED):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "The public key operation failed.");
break;
case (MBEDTLS_ERR_RSA_PRIVATE_FAILED):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "The private key operation failed.");
break;
case (MBEDTLS_ERR_RSA_VERIFY_FAILED):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "The PKCS#1 verification failed.");
break;
case (MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "The output buffer for decryption is not large enough.");
break;
case (MBEDTLS_ERR_RSA_RNG_FAILED):
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "The random generator failed to generate non-zeros.");
break;
default:
throw tc::crypto::CryptoException("RsaImpl::publicTransform()", "An unexpected error occurred.");
}
}
void tc::crypto::detail::RsaImpl::privateTransform(byte_t* dst, const byte_t* src)
{
if (mState != State::Initialized) { return; }
if (dst == nullptr) { throw tc::ArgumentNullException("RsaImpl::privateTransform()", "dst was null."); }
if (src == nullptr) { throw tc::ArgumentNullException("RsaImpl::privateTransform()", "src was null."); }
int ret = mbedtls_rsa_private(&(mImplCtx->mContext), nullptr, nullptr, src, dst);
switch (ret)
{
case (0):
break;
case (MBEDTLS_ERR_RSA_BAD_INPUT_DATA):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "Bad input parameters to function.");
break;
case (MBEDTLS_ERR_RSA_INVALID_PADDING):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "Input data contains invalid padding and is rejected.");
break;
case (MBEDTLS_ERR_RSA_KEY_GEN_FAILED):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "Something failed during generation of a key.");
break;
case (MBEDTLS_ERR_RSA_KEY_CHECK_FAILED):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "Key failed to pass the validity check of the library.");
break;
case (MBEDTLS_ERR_RSA_PUBLIC_FAILED):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "The public key operation failed.");
break;
case (MBEDTLS_ERR_RSA_PRIVATE_FAILED):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "The private key operation failed.");
break;
case (MBEDTLS_ERR_RSA_VERIFY_FAILED):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "The PKCS#1 verification failed.");
break;
case (MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "The output buffer for decryption is not large enough.");
break;
case (MBEDTLS_ERR_RSA_RNG_FAILED):
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "The random generator failed to generate non-zeros.");
break;
default:
throw tc::crypto::CryptoException("RsaImpl::privateTransform()", "An unexpected error occurred.");
}
}
@@ -1,85 +0,0 @@
#include <tc/crypto/detail/RsaKeyGeneratorImpl.h>
#include <mbedtls/rsa.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
const std::string tc::crypto::detail::RsaKeyGeneratorImpl::kClassName = "tc::crypto::detail::RsaKeyGeneratorImpl";
struct tc::crypto::detail::RsaKeyGeneratorImpl::ImplCtx
{
mbedtls_rsa_context rsa;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_context entropy;
};
tc::crypto::detail::RsaKeyGeneratorImpl::RsaKeyGeneratorImpl() :
mImplCtx(new ImplCtx())
{
mbedtls_entropy_init( &(mImplCtx->entropy) );
mbedtls_ctr_drbg_init( &(mImplCtx->ctr_drbg) );
mbedtls_rsa_init( &(mImplCtx->rsa), 0, 0 );
int ret = mbedtls_ctr_drbg_seed(&(mImplCtx->ctr_drbg), mbedtls_entropy_func, &(mImplCtx->entropy), (const unsigned char *)kClassName.c_str(), kClassName.size());
switch (ret)
{
case (0):
break;
case (MBEDTLS_ERR_ENTROPY_SOURCE_FAILED):
throw tc::crypto::CryptoException(kClassName, "mbedtls_ctr_drbg_seed() Entropy source failed");
default:
throw tc::crypto::CryptoException(kClassName, "mbedtls_ctr_drbg_seed() An unexpected error occurred");
}
}
tc::crypto::detail::RsaKeyGeneratorImpl::~RsaKeyGeneratorImpl()
{
mbedtls_rsa_free( &(mImplCtx->rsa) );
mbedtls_ctr_drbg_free( &(mImplCtx->ctr_drbg) );
mbedtls_entropy_free( &(mImplCtx->entropy) );
}
void tc::crypto::detail::RsaKeyGeneratorImpl::generateKey(size_t key_bit_size, byte_t* n, size_t n_size, byte_t* p, size_t p_size, byte_t* q, size_t q_size, byte_t* d, size_t d_size, byte_t* e, size_t e_size)
{
if ((key_bit_size % 8) != 0) { throw tc::ArgumentOutOfRangeException(kClassName, "key_bit_size was not a multiple of 8 bits."); }
if (n != nullptr && n_size < (key_bit_size/8)) { throw tc::ArgumentNullException(kClassName, "n was not null, but n_size was not large enough"); }
if (p != nullptr && p_size < (key_bit_size/8)/2) { throw tc::ArgumentNullException(kClassName, "p was not null, but p_size was not large enough"); }
if (q != nullptr && q_size < (key_bit_size/8)/2) { throw tc::ArgumentNullException(kClassName, "q was not null, but q_size was not large enough"); }
if (d != nullptr && d_size < (key_bit_size/8)) { throw tc::ArgumentNullException(kClassName, "d was not null, but d_size was not large enough"); }
if (e != nullptr && e_size < 3) { throw tc::ArgumentNullException(kClassName, "e was not null, but e_size was not large enough"); }
int ret = 1;
// generate key
ret = mbedtls_rsa_gen_key(&(mImplCtx->rsa), mbedtls_ctr_drbg_random, &(mImplCtx->ctr_drbg), uint32_t(key_bit_size), 0x10001);
switch (ret)
{
case (0):
break;
case (MBEDTLS_ERR_RSA_KEY_GEN_FAILED):
throw tc::crypto::CryptoException(kClassName, "mbedtls_rsa_gen_key() Something failed during generation of a key.");
case (MBEDTLS_ERR_RSA_RNG_FAILED):
throw tc::crypto::CryptoException(kClassName, "mbedtls_rsa_gen_key() The random generator failed to generate non-zeros.");
default:
throw tc::crypto::CryptoException(kClassName, "mbedtls_rsa_gen_key() An unexpected error occurred.");
}
// export key from mbedtls context
ret = mbedtls_rsa_export_raw(&(mImplCtx->rsa), \
n, n_size, \
p, p_size, \
q, q_size, \
d, d_size, \
e, e_size \
);
switch (ret)
{
case (0):
break;
default:
throw tc::crypto::CryptoException(kClassName, "mbedtls_rsa_export_raw() An unexpected error occurred.");
}
// clear key from mbedtls context
mbedtls_rsa_init( &(mImplCtx->rsa), 0, 0 );
}
@@ -1,44 +0,0 @@
#include <tc/crypto/detail/Sha1Impl.h>
#include <mbedtls/md.h>
struct tc::crypto::detail::Sha1Impl::ImplCtx
{
mbedtls_md_context_t mMdContext;
};
tc::crypto::detail::Sha1Impl::Sha1Impl() :
mState(State::None),
mImplCtx(new ImplCtx())
{
mbedtls_md_init(&(mImplCtx->mMdContext));
mbedtls_md_setup(&(mImplCtx->mMdContext), mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 0);
}
tc::crypto::detail::Sha1Impl::~Sha1Impl()
{
mbedtls_md_free(&(mImplCtx->mMdContext));
}
void tc::crypto::detail::Sha1Impl::initialize()
{
mbedtls_md_starts(&(mImplCtx->mMdContext));
mState = State::Initialized;
}
void tc::crypto::detail::Sha1Impl::update(const byte_t* src, size_t src_size)
{
mbedtls_md_update(&(mImplCtx->mMdContext), src, src_size);
}
void tc::crypto::detail::Sha1Impl::getHash(byte_t* hash)
{
if (mState == State::Initialized)
{
mbedtls_md_finish(&(mImplCtx->mMdContext), mHash.data());
mState = State::Done;
}
if (mState == State::Done)
{
memcpy(hash, mHash.data(), mHash.size());
}
}
@@ -1,58 +0,0 @@
#include <tc/crypto/detail/Sha2Impl.h>
#include <mbedtls/md.h>
struct tc::crypto::detail::Sha2Impl::ImplCtx
{
mbedtls_md_context_t mMdContext;
};
tc::crypto::detail::Sha2Impl::Sha2Impl(SHA2BitSize algo) :
mState(State::None),
mHashSize(0),
mImplCtx(new ImplCtx())
{
mbedtls_md_init(&(mImplCtx->mMdContext));
switch(algo)
{
case (SHA2BitSize_256):
mHashSize = kSha2_256_HashSize;
mbedtls_md_setup(&(mImplCtx->mMdContext), mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 0);
break;
case (SHA2BitSize_512):
mHashSize = kSha2_512_HashSize;
mbedtls_md_setup(&(mImplCtx->mMdContext), mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), 0);
break;
default:
throw tc::crypto::CryptoException("tc::crypto::detail::Sha2Impl", "Invalid value for SHA2BitSize");
}
}
tc::crypto::detail::Sha2Impl::~Sha2Impl()
{
mbedtls_md_free(&(mImplCtx->mMdContext));
}
void tc::crypto::detail::Sha2Impl::initialize()
{
mbedtls_md_starts(&(mImplCtx->mMdContext));
mState = State::Initialized;
}
void tc::crypto::detail::Sha2Impl::update(const byte_t* src, size_t src_size)
{
mbedtls_md_update(&(mImplCtx->mMdContext), src, src_size);
}
void tc::crypto::detail::Sha2Impl::getHash(byte_t* hash)
{
if (mState == State::Initialized)
{
mbedtls_md_finish(&(mImplCtx->mMdContext), mHash.data());
mState = State::Done;
}
if (mState == State::Done)
{
memcpy(hash, mHash.data(), mHashSize);
}
}
@@ -1,97 +0,0 @@
#include <tc/io/BasicPathResolver.h>
const std::string tc::io::BasicPathResolver::kClassName = "tc::io::BasicPathResolver";
tc::io::BasicPathResolver::BasicPathResolver() :
BasicPathResolver(tc::io::Path("/"), {})
{}
tc::io::BasicPathResolver::BasicPathResolver(const tc::io::Path& current_directory_path) :
BasicPathResolver(current_directory_path, {})
{}
tc::io::BasicPathResolver::BasicPathResolver(const tc::io::Path& current_directory_path, const std::vector<std::string>& root_names) :
mCurrentDirPath(),
mExplicitRootLabels(root_names)
{
setCurrentDirectory(current_directory_path);
}
void tc::io::BasicPathResolver::setCurrentDirectory(const tc::io::Path& path)
{
if (path.empty())
{
throw tc::ArgumentOutOfRangeException(kClassName, "path was empty.");
}
mCurrentDirPath = path;
}
const tc::io::Path& tc::io::BasicPathResolver::getCurrentDirectory() const
{
return mCurrentDirPath;
}
void tc::io::BasicPathResolver::setExplicitRootLabels(const std::vector<std::string>& root_labels)
{
mExplicitRootLabels = root_labels;
}
const std::vector<std::string>& tc::io::BasicPathResolver::getExplicitRootLabels() const
{
return mExplicitRootLabels;
}
void tc::io::BasicPathResolver::resolveCanonicalPath(const tc::io::Path& path, tc::io::Path& canonical_path) const
{
canonical_path = resolveCanonicalPath(path);
}
tc::io::Path tc::io::BasicPathResolver::resolveCanonicalPath(const tc::io::Path& path) const
{
// create output path
tc::io::Path canonical_path;
// get iterator for input path
auto path_itr = path.begin();
// if the begining of the path exists and is a valid root label, then the input path is an absolute (but not necessarily canonical) path
if (path_itr != path.end() && (std::find(mExplicitRootLabels.begin(), mExplicitRootLabels.end(), *path_itr) != mExplicitRootLabels.end() || *path_itr == mCurrentDirPath.front()))
{
// the beginning of canonical_path is the path root name
canonical_path = tc::io::Path(*path_itr + "/");
// increment path iterator
path_itr++;
}
else
{
// the beginning of the canonical_path is the current directory path
canonical_path = mCurrentDirPath;
}
// process relative elements of path, combining with the base canonical_path
for (; path_itr != path.end(); path_itr++)
{
// ignore "current directory" alias
if (*path_itr == ".")
continue;
// ignore empty path elements
else if (*path_itr == "")
continue;
// navigate up for "parent directory" alias
else if (*path_itr == "..")
{
// ".." is the parent directory, so if there are path elements then we remove from the back to "go to the parent directory"
if (canonical_path.size() > 1)
canonical_path.pop_back();
else
continue;
}
else
canonical_path.push_back(*path_itr);
}
return canonical_path;
}
@@ -1,370 +0,0 @@
#include <tc/io/ConcatenatedStream.h>
#include <tc/io/StreamUtil.h>
#include <tc/io/IOUtil.h>
const std::string tc::io::ConcatenatedStream::kClassName = "tc::io::ConcatenatedStream";
tc::io::ConcatenatedStream::ConcatenatedStream() :
mStreamList(),
mStreamListMap(),
mCurrentStream(),
mCanRead(false),
mCanWrite(false),
mCanSeek(false),
mStreamLength(0)
{}
tc::io::ConcatenatedStream::ConcatenatedStream(ConcatenatedStream&& other) :
ConcatenatedStream()
{
*this = std::move(other);
}
tc::io::ConcatenatedStream::ConcatenatedStream(const std::vector<std::shared_ptr<tc::io::IStream>>& stream_list) :
ConcatenatedStream()
{
// track the overall stream properties
bool can_read = true;
bool can_write = true;
bool can_seek = true;
// reset stream length
mStreamLength = 0;
// process stream list
for (auto itr = stream_list.begin(); itr != stream_list.end(); itr++)
{
// skip null streams
if (*itr == nullptr)
continue;
// skip empty streams
if ((*itr)->length() == 0)
continue;
// skip streams that can't be read or writen to (so it's useless)
if ((*itr)->canRead() == false && (*itr)->canWrite() == false)
continue;
// create stream info for the input stream
StreamInfo info;
// range is from the current concatenated stream position for the length of the input stream
info.range = StreamRange(mStreamLength, (*itr)->length());
info.stream = *itr;
// throw an exception if the input stream range overlaps with an existing range (which shouldn't be possible)
if (mStreamListMap.find(info.range) != mStreamListMap.end())
{
throw tc::Exception(kClassName, "Poor state management detected.");
}
if (info.stream->canRead() == false)
can_read = false;
if (info.stream->canWrite() == false)
can_write = false;
if (info.stream->canSeek() == false)
can_seek = false;
mStreamListMap.insert(std::pair<StreamRange, size_t>(info.range, mStreamList.size()));
mStreamList.push_back(info);
mStreamLength += info.range.length;
}
// check the stream is usable
if (!can_read && !can_write)
{
throw tc::NotSupportedException(kClassName, "Stream does not support read or write.");
}
// check the stream is usable
if (mStreamLength == 0)
{
throw tc::NotSupportedException(kClassName, "Stream had no length.");
}
// save iterator to current stream
mCurrentStream = mStreamList.begin();
// save properties
mCanRead = can_read;
mCanWrite = can_write;
mCanSeek = can_seek;
}
tc::io::ConcatenatedStream::~ConcatenatedStream()
{
dispose();
}
tc::io::ConcatenatedStream& tc::io::ConcatenatedStream::operator=(tc::io::ConcatenatedStream&& other)
{
mStreamList = std::move(other.mStreamList);
mStreamListMap = std::move(other.mStreamListMap);
mCurrentStream = std::move(other.mCurrentStream);
mCanRead = other.mCanRead;
mCanWrite = other.mCanWrite;
mCanSeek = other.mCanSeek;
mStreamLength = other.mStreamLength;
// clear other state
other.mStreamList.clear();
other.mStreamListMap.clear();
other.mCurrentStream.makeNull();
other.mCanRead = false;
other.mCanWrite = false;
other.mCanSeek = false;
other.mStreamLength = 0;
return *this;
}
bool tc::io::ConcatenatedStream::canRead() const
{
return isStreamDisposed() ? false : mCanRead;
}
bool tc::io::ConcatenatedStream::canWrite() const
{
return isStreamDisposed() ? false : mCanWrite;
}
bool tc::io::ConcatenatedStream::canSeek() const
{
return isStreamDisposed() ? false : mCanSeek;
}
int64_t tc::io::ConcatenatedStream::length()
{
return isStreamDisposed() ? 0 : mStreamLength;
}
int64_t tc::io::ConcatenatedStream::position()
{
return isStreamDisposed() ? 0 : (mCurrentStream.get()->range.offset + mCurrentStream.get()->stream->position());
}
size_t tc::io::ConcatenatedStream::read(byte_t* ptr, size_t count)
{
if (isStreamDisposed())
{
throw tc::ObjectDisposedException(kClassName+"read()", "Stream wasd.");
}
if (mCanRead == false)
{
throw tc::NotSupportedException(kClassName+"read()", "Stream does not support reading.");
}
// read
size_t readable_count = IOUtil::getReadableCount(mStreamLength, position(), count);
size_t remaining_readable_count = readable_count;
do {
// determine expected readable data count for the current stream
size_t readable_count_for_current_stream = IOUtil::getReadableCount(mCurrentStream.get()->range.length, mCurrentStream.get()->stream->position(), remaining_readable_count);
if (readable_count_for_current_stream != 0)
{
// read data and throw exception if unexpected read count is returned
if (readable_count_for_current_stream != mCurrentStream.get()->stream->read(ptr + (readable_count - remaining_readable_count), readable_count_for_current_stream))
{
throw tc::io::IOException(kClassName+"read()", "Reading from one of the base streams returned less data than expected.");
}
// decrement the remaining readable count
remaining_readable_count -= readable_count_for_current_stream;
}
// if there is more data to be read, increment the current stream
if (remaining_readable_count != 0)
{
updateCurrentStream(mCurrentStream.get() + 1);
// make sure we haven't somehow reached the end before we expected
if (mCurrentStream.get() == mStreamList.end())
{
throw tc::io::IOException(kClassName+"read()", "More data was expected to be readable but end of stream list was reached.");
}
// correct the position the 0x0 if not already
if (mCurrentStream.get()->stream->position() != 0x0)
{
if (!mCanSeek)
{
throw tc::io::IOException(kClassName+"read()", "Tried to continue reading from the next stream but the position was not 0, and seek was not supported.");
}
mCurrentStream.get()->stream->seek(0, tc::io::SeekOrigin::Begin);
}
}
} while (remaining_readable_count > 0);
return readable_count;
}
size_t tc::io::ConcatenatedStream::write(const byte_t* ptr, size_t count)
{
if (isStreamDisposed())
{
throw tc::ObjectDisposedException(kClassName+"write()", "Stream was disposed.");
}
if (mCanWrite == false)
{
throw tc::NotSupportedException(kClassName+"write()", "Stream does not support writing.");
}
// write
size_t writable_count = IOUtil::getWritableCount(mStreamLength, position(), count);
size_t remaining_writable_count = writable_count;
do {
// determine expected writable data count for the current stream
size_t writable_count_for_current_stream = IOUtil::getWritableCount(mCurrentStream.get()->range.length, mCurrentStream.get()->stream->position(), remaining_writable_count);
if (writable_count_for_current_stream != 0)
{
// write data and throw exception if unexpected write count is returned
if (writable_count_for_current_stream != mCurrentStream.get()->stream->write(ptr + (writable_count - remaining_writable_count), writable_count_for_current_stream))
{
throw tc::io::IOException(kClassName+"write()", "Writing from one of the base streams returned less data than expected.");
}
// decrement the remaining writable count
remaining_writable_count -= writable_count_for_current_stream;
}
// if there is more data to be write, increment the current stream
if (remaining_writable_count != 0)
{
updateCurrentStream(mCurrentStream.get() + 1);
// make sure we haven't somehow reached the end before we expected
if (mCurrentStream.get() == mStreamList.end())
{
throw tc::io::IOException(kClassName+"write()", "More data was expected to be writable but end of stream list was reached.");
}
// correct the position the 0x0 if not already
if (mCurrentStream.get()->stream->position() != 0x0)
{
if (!mCanSeek)
{
throw tc::io::IOException(kClassName+"write()", "Tried to continue writing from the next stream but the position was not 0, and seek was not supported.");
}
mCurrentStream.get()->stream->seek(0, tc::io::SeekOrigin::Begin);
}
}
} while (remaining_writable_count > 0);
return writable_count;
}
int64_t tc::io::ConcatenatedStream::seek(int64_t offset, SeekOrigin origin)
{
if (isStreamDisposed())
{
throw tc::ObjectDisposedException(kClassName+"seek()", "Stream was disposed.");
}
if (mCanSeek == false)
{
throw tc::NotSupportedException(kClassName+"seek()", "Stream does not support seeking.");
}
// seek
int64_t absolute_seek_pos = StreamUtil::getSeekResult(offset, origin, position(), mStreamLength);
// seek is <= 0 : we use the first stream and set the position to 0
if (absolute_seek_pos <= 0)
{
updateCurrentStream(mStreamList.begin());
if (mCurrentStream.get() == mStreamList.end())
{
throw tc::io::IOException(kClassName+"seek()", "Failed to seek because underlying stream could not be determined.");
}
mCurrentStream.get()->stream->seek(0, tc::io::SeekOrigin::Begin);
}
// seek is < mStreamLength : we find the stream in the map and set the relative position
else if (absolute_seek_pos < mStreamLength)
{
// before we do a map lookup, check if the current stream has the range the offset sits in
if ((absolute_seek_pos >= mCurrentStream.get()->range.offset) && (absolute_seek_pos < (mCurrentStream.get()->range.offset + mCurrentStream.get()->range.length)))
{
mCurrentStream.get()->stream->seek(absolute_seek_pos - mCurrentStream.get()->range.offset, tc::io::SeekOrigin::Begin);
}
// look up the correct stream in the map
else
{
auto rangeItr = mStreamListMap.find(StreamRange(absolute_seek_pos));
if (rangeItr == mStreamListMap.end())
{
throw tc::io::IOException(kClassName+"seek()", "Failed to seek because underlying stream could not be determined.");
}
if (rangeItr->second > mStreamList.size())
{
throw tc::io::IOException(kClassName+"seek()", "Failed to seek because underlying stream could not be determined.");
}
updateCurrentStream(mStreamList.begin() + rangeItr->second);
mCurrentStream.get()->stream->seek(absolute_seek_pos - mCurrentStream.get()->range.offset, tc::io::SeekOrigin::Begin);
}
}
// seek is >= mStreamLength : we use the end stream and seek to the end of it
else
{
updateCurrentStream(--mStreamList.end());
if (mCurrentStream.get() == mStreamList.end())
{
throw tc::io::IOException(kClassName+"seek()", "Failed to seek because underlying stream could not be determined.");
}
mCurrentStream.get()->stream->seek(0, tc::io::SeekOrigin::End);
}
return position();
}
void tc::io::ConcatenatedStream::setLength(int64_t length)
{
if (isStreamDisposed())
{
throw tc::ObjectDisposedException(kClassName+"setLength()", "Stream was disposed.");
}
throw tc::NotImplementedException(kClassName+"setLength()", "setLength() is not implemented for tc::io::ConcatenatedStream.");
}
void tc::io::ConcatenatedStream::flush()
{
if (isStreamDisposed())
{
throw tc::ObjectDisposedException(kClassName+"flush()", "Stream was disposed.");
}
mCurrentStream.get()->stream->flush();
}
void tc::io::ConcatenatedStream::dispose()
{
if (isStreamDisposed() == false)
mCurrentStream.get()->stream->flush();
mStreamList.clear();
mCurrentStream.makeNull();
mCanRead = false;
mCanWrite = false;
mCanSeek = false;
mStreamLength = 0;
}
void tc::io::ConcatenatedStream::updateCurrentStream(std::vector<StreamInfo>::iterator stream_itr)
{
if (mCurrentStream.isNull())
{
mCurrentStream = stream_itr;
}
else if (mCurrentStream.get() != stream_itr)
{
// if stream itr != end() flush the stream
if (mCurrentStream.get() != mStreamList.end())
mCurrentStream.get()->stream->flush();
mCurrentStream = stream_itr;
}
}
@@ -1,752 +0,0 @@
#include <tc/io/FileStream.h>
#include <tc/PlatformErrorHandlingUtil.h>
#ifdef _WIN32
#include <direct.h>
#include <cstdlib>
#else
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h> /* For O_RDWR */
#include <unistd.h> /* For open(), creat() */
#endif
const std::string tc::io::FileStream::kClassName = "tc::io::FileStream";
tc::io::FileStream::FileHandle::~FileHandle()
{
#ifdef _WIN32
CloseHandle(handle);
#else
::close(handle);
#endif
}
tc::io::FileStream::FileStream() :
mCanRead(false),
mCanWrite(false),
mCanSeek(false),
mIsAppendRestrictSeekCall(false),
mFileHandle()
{}
tc::io::FileStream::FileStream(FileStream&& other) :
FileStream()
{
*this = std::move(other);
}
tc::io::FileStream::FileStream(const tc::io::Path& path, FileMode mode, FileAccess access) :
FileStream()
{
// dispose stream before opening new stream
dispose();
open_impl(path, mode, access);
}
tc::io::FileStream& tc::io::FileStream::operator=(tc::io::FileStream&& other)
{
mCanRead = other.mCanRead;
mCanWrite = other.mCanWrite;
mCanSeek = other.mCanSeek;
mIsAppendRestrictSeekCall = other.mIsAppendRestrictSeekCall;
mFileHandle = std::move(other.mFileHandle);
other.dispose();
return *this;
}
bool tc::io::FileStream::canRead() const
{
return mFileHandle == nullptr ? false : mCanRead;
}
bool tc::io::FileStream::canWrite() const
{
return mFileHandle == nullptr ? false : mCanWrite;
}
bool tc::io::FileStream::canSeek() const
{
return mFileHandle == nullptr || mIsAppendRestrictSeekCall == true ? false : mCanSeek;
}
int64_t tc::io::FileStream::length()
{
return mFileHandle == nullptr ? 0 : length_impl();
}
int64_t tc::io::FileStream::position()
{
if (mFileHandle == nullptr)
{
return 0;
}
if (mCanSeek == false)
{
throw tc::NotSupportedException(kClassName+"::position()", "This method is not supported for streams that do not support seeking");
}
return seek_impl(0, SeekOrigin::Current);
}
size_t tc::io::FileStream::read(byte_t* ptr, size_t count)
{
if (mFileHandle == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::read()", "Failed to read from stream (stream is disposed)");
}
if (mCanRead == false)
{
throw tc::NotSupportedException(kClassName+"::read()", "Stream does not support reading");
}
if (ptr == nullptr)
{
throw tc::ArgumentNullException(kClassName+"::read()", "ptr was null");
}
if (count < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName+"::read()", "count was negative");
}
return read_impl(ptr, count);
}
size_t tc::io::FileStream::write(const byte_t* ptr, size_t count)
{
if (mFileHandle == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::write()", "Failed to write to stream (no file open)");
}
if (mCanWrite == false)
{
throw tc::NotSupportedException(kClassName+"::write()", "Stream does not support writing");
}
if (ptr == nullptr)
{
throw tc::ArgumentNullException(kClassName+"::write()", "ptr was null");
}
if (count < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName+"::write()", "count was negative");
}
return write_impl(ptr, count);
}
int64_t tc::io::FileStream::seek(int64_t offset, SeekOrigin origin)
{
if (mFileHandle == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::seek()", "Failed to set stream position (stream is disposed)");
}
if (mCanSeek == false)
{
throw tc::NotSupportedException(kClassName+"::seek()", "Stream does not support seeking");
}
if (mIsAppendRestrictSeekCall == true)
{
throw tc::io::IOException(kClassName+"::seek()", "Streams opened in Append mode are not allowed to change file position.");
}
return seek_impl(offset, origin);
}
void tc::io::FileStream::setLength(int64_t length)
{
if (mFileHandle == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::setLength()", "Failed to set stream length (stream is disposed)");
}
if (mCanWrite == false || mCanSeek == false)
{
throw tc::NotSupportedException(kClassName+"::setLength()", "Stream does not support both writing and seeking");
}
setLength_impl(length);
}
void tc::io::FileStream::flush()
{
if (mFileHandle != nullptr)
{
flush_impl();
}
}
void tc::io::FileStream::dispose()
{
if (mFileHandle.get() != nullptr)
{
flush();
mFileHandle.reset();
}
mCanRead = false;
mCanWrite = false;
mCanSeek = false;
}
#ifdef _WIN32
#pragma warning(disable : 4065) // disable warning for switch case with only default case
void tc::io::FileStream::open_impl(const tc::io::Path& path, FileMode mode, FileAccess access)
{
// convert Path to unicode string
std::u16string unicode_path = path.to_u16string(tc::io::Path::Format::Win32);
DWORD access_flag = 0;
DWORD share_mode_flag = 0;
DWORD creation_flag = 0;
// process mode
switch (mode)
{
case (FileMode::CreateNew):
// create file if does not exist | return error if file does not exist
creation_flag = CREATE_NEW;
break;
case (FileMode::Create):
// create file if does not exist | truncate file if it exists
creation_flag = CREATE_ALWAYS;
break;
case (FileMode::Open):
// no flags
creation_flag = OPEN_EXISTING;
break;
case (FileMode::OpenOrCreate):
// create file if does not exist
creation_flag = access == FileAccess::Read ? OPEN_EXISTING : OPEN_ALWAYS;
break;
case (FileMode::Truncate):
// truncate file if file exists
creation_flag = TRUNCATE_EXISTING;
break;
case (FileMode::Append):
// open in append mode
creation_flag = OPEN_ALWAYS;
break;
default:
throw tc::ArgumentOutOfRangeException(kClassName+"::open()", "Illegal value for mode");
}
// process access
switch (access)
{
case (FileAccess::Read):
// read access
access_flag = GENERIC_READ;
// shared read lock
share_mode_flag = FILE_SHARE_READ;
break;
case (FileAccess::Write):
// write access
access_flag = GENERIC_WRITE;
// exclusive lock
share_mode_flag = 0;
break;
case (FileAccess::ReadWrite):
// read/write access
access_flag = GENERIC_READ | GENERIC_WRITE;
// exclusive lock
share_mode_flag = 0;
break;
default:
throw tc::ArgumentOutOfRangeException(kClassName+"::open()", "Illegal value for access");
}
// validate use of write dependent flags (open existing is the only one that supports no write flag)
if (creation_flag != OPEN_EXISTING && !(access_flag & GENERIC_WRITE))
{
throw tc::ArgumentException(kClassName + "::open()", "Stream open mode requires write access, but write access was not allowed");
}
// append can only open in write only mode
if (mode == tc::io::FileMode::Append && (access_flag & GENERIC_READ | GENERIC_WRITE) != GENERIC_WRITE)
{
throw tc::ArgumentException(kClassName + "::open()", "Stream opened in Append mode can only work with Write access. ReadWrite is not permitted");
}
// open file
HANDLE file_handle = CreateFileW((LPCWSTR)unicode_path.c_str(),
access_flag,
share_mode_flag,
0,
creation_flag,
FILE_ATTRIBUTE_NORMAL,
NULL);
// check file handle
if (file_handle == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
switch (error)
{
case (ERROR_FILE_NOT_FOUND):
case (ERROR_PATH_NOT_FOUND):
throw tc::io::FileNotFoundException(kClassName+"::open()", PlatformErrorHandlingUtil::GetLastErrorString(error));
case (ERROR_FILE_EXISTS):
throw tc::io::FileExistsException(kClassName+"::open()", PlatformErrorHandlingUtil::GetLastErrorString(error));
case (ERROR_INVALID_PARAMETER):
throw tc::ArgumentException(kClassName + "::open()", PlatformErrorHandlingUtil::GetLastErrorString(error));
case (ERROR_ACCESS_DENIED):
throw tc::UnauthorisedAccessException(kClassName+"::open()", PlatformErrorHandlingUtil::GetLastErrorString(error));
default:
throw tc::io::IOException(kClassName+"::open()", "Failed to open file stream (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
// store file handle
mFileHandle = std::unique_ptr<tc::io::FileStream::FileHandle>(new tc::io::FileStream::FileHandle(file_handle));
// seek to end of file if in append mode
if (mode == FileMode::Append)
{
seek_impl(0, SeekOrigin::End);
mIsAppendRestrictSeekCall = true;
}
// set state flags
mCanRead = (access_flag & GENERIC_READ) ? true : false;
mCanWrite = (access_flag & GENERIC_WRITE) ? true : false;
mCanSeek = GetFileType(mFileHandle->handle) == FILE_TYPE_DISK ? true : false;
}
int64_t tc::io::FileStream::length_impl()
{
LARGE_INTEGER stream_length;
if (GetFileSizeEx(mFileHandle->handle, &stream_length) == false)
{
DWORD error = GetLastError();
switch (error)
{
// TODO: Directly handle usual errors for custom exceptions
default:
throw tc::io::IOException(kClassName+"::length()", "Failed to get stream length (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
return (int64_t) stream_length.QuadPart;
}
size_t tc::io::FileStream::read_impl(byte_t* ptr, size_t count)
{
DWORD bytes_read;
if (ReadFile(mFileHandle->handle, ptr, (DWORD)count, &bytes_read, NULL) == false)
{
DWORD error = GetLastError();
switch (error)
{
// TODO: Directly handle usual errors for custom exceptions
default:
throw tc::io::IOException(kClassName+"::read()", "Failed to read from stream (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
return bytes_read;
}
size_t tc::io::FileStream::write_impl(const byte_t* ptr, size_t count)
{
DWORD bytes_written;
if (WriteFile(mFileHandle->handle, ptr, (DWORD)count, &bytes_written, NULL) == false)
{
DWORD error = GetLastError();
switch (error)
{
// TODO: Directly handle usual errors for custom exceptions
default:
throw tc::io::IOException(kClassName+"::write()", "Failed to write to stream (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
return bytes_written;
}
int64_t tc::io::FileStream::seek_impl(int64_t offset, SeekOrigin origin)
{
DWORD seek_flag = 0;
switch(origin)
{
case (SeekOrigin::Begin):
seek_flag = FILE_BEGIN;
break;
case (SeekOrigin::Current):
seek_flag = FILE_CURRENT;
break;
case (SeekOrigin::End):
seek_flag = FILE_END;
break;
default:
throw tc::ArgumentOutOfRangeException(kClassName+"::seek()", "Unknown SeekOrigin value");
}
LARGE_INTEGER win_pos, out;
win_pos.QuadPart = offset;
if (SetFilePointerEx(
mFileHandle->handle,
win_pos,
&out,
seek_flag
) == false)
{
DWORD error = GetLastError();
switch (error)
{
case (ERROR_NEGATIVE_SEEK):
throw tc::ArgumentOutOfRangeException(kClassName+"::seek()", PlatformErrorHandlingUtil::GetLastErrorString(error));
default:
throw tc::io::IOException(kClassName+"::seek()", "Failed to set stream position (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
return out.QuadPart;
}
void tc::io::FileStream::setLength_impl(int64_t length)
{
seek(length, tc::io::SeekOrigin::Begin);
if (SetEndOfFile(
mFileHandle->handle
) == false)
{
DWORD error = GetLastError();
switch (error)
{
default:
throw tc::io::IOException(kClassName+"::setLength()", "Failed to set end of file (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
}
void tc::io::FileStream::flush_impl()
{
if (mCanWrite)
{
// flush buffers only applies to written data
FlushFileBuffers(mFileHandle->handle);
}
}
#pragma warning(default : 4065) // reenable warning for switch case with only default case
#else
void tc::io::FileStream::open_impl(const tc::io::Path& path, FileMode mode, FileAccess access)
{
// convert Path to unicode string
std::string unicode_path = path.to_string(tc::io::Path::Format::POSIX);
// open file
int open_flag = 0;
// process mode
switch (mode)
{
case (FileMode::CreateNew):
// create file if does not exist | return error if file does not exist
open_flag |= O_CREAT | O_EXCL;
break;
case (FileMode::Create):
// create file if does not exist | truncate file if it exists
open_flag |= O_CREAT | O_TRUNC;
break;
case (FileMode::Open):
// no flags
open_flag |= 0;
break;
case (FileMode::OpenOrCreate):
// create file if does not exist (however only enable create flag if write access is enabled)
open_flag |= (access == FileAccess::ReadWrite || access == FileAccess::Write) ? O_CREAT : 0;
break;
case (FileMode::Truncate):
// truncate file if file exists
open_flag |= O_TRUNC;
break;
case (FileMode::Append):
// open in append mode (create file if doesn't exist)
open_flag |= O_APPEND | O_CREAT;
break;
default:
throw tc::ArgumentOutOfRangeException(kClassName+"::open()", "Illegal value for mode");
}
// process access
switch (access)
{
case (FileAccess::Read):
// read access
open_flag |= O_RDONLY;
#ifdef O_SHLOCK
// shared lock
open_flag |= O_SHLOCK;
#endif
break;
case (FileAccess::Write):
// write access
open_flag |= O_WRONLY;
#ifdef O_EXLOCK
// exclusive lock
open_flag |= O_EXLOCK;
#endif
break;
case (FileAccess::ReadWrite):
// read/write access
open_flag |= O_RDWR;
#ifdef O_EXLOCK
// exclusive lock
open_flag |= O_EXLOCK;
#endif
break;
default:
throw tc::ArgumentOutOfRangeException(kClassName+"::open()", "Illegal value for access");
}
// validate use of write dependent flags
if ((open_flag & (O_APPEND | O_TRUNC | O_CREAT)) && !(open_flag & (O_WRONLY|O_RDWR)))
{
throw tc::ArgumentException(kClassName+"::open()", "Stream open mode requires write access, but write access was not allowed");
}
// explicitly check APPEND as being write only
if ((open_flag & (O_APPEND)) && (open_flag & (O_RDWR)))
{
throw tc::ArgumentException(kClassName+"::open()", "Stream opened in Append mode can only work with Write access. ReadWrite is not permitted");
}
// open file handle with Read/Write for User, Read for Group, nothing for others
int file_handle = ::open(unicode_path.c_str(), open_flag, S_IRUSR | S_IWUSR | S_IRGRP);
// handle error
if (file_handle == -1)
{
switch (errno)
{
case (EACCES):
case (EROFS):
throw tc::UnauthorisedAccessException(kClassName+"::open()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENAMETOOLONG):
throw tc::io::PathTooLongException(kClassName+"::open()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENOENT):
throw tc::io::FileNotFoundException(kClassName+"::open()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EEXIST):
throw tc::io::FileExistsException(kClassName+"::open()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EINVAL):
throw tc::ArgumentOutOfRangeException(kClassName+"::open()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EFAULT):
throw tc::AccessViolationException(kClassName+"::open()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EISDIR):
throw tc::io::FileNotFoundException(kClassName+"::open()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EDQUOT):
case (EFBIG):
case (EINTR):
case (ELOOP):
case (EMFILE):
case (ENFILE):
case (ENOMEM):
case (ENOSPC):
case (ENXIO):
case (EOVERFLOW):
case (EPERM):
case (ETXTBSY):
case (EWOULDBLOCK):
default:
throw tc::io::IOException(kClassName+"::open()", "Failed to open file stream (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
// store file handle
mFileHandle = std::unique_ptr<tc::io::FileStream::FileHandle>(new tc::io::FileStream::FileHandle(file_handle));
// get stat info on file
struct stat stat_buf;
if (fstat(mFileHandle->handle, &stat_buf) == -1)
{
throw tc::io::IOException(kClassName+"::open()", "Failed to check stream properties using fstat() (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
// if this is a directory throw an exception
if (S_ISDIR(stat_buf.st_mode))
{
throw tc::io::FileNotFoundException(kClassName+"::open()", "Path refers to a directory not a file");
}
// set state flags
// would check O_RDONLY but that resolves to 0 so it can't be bitmask checked
mCanRead = (open_flag & O_RDWR) || !(open_flag & O_WRONLY) ? true : false;
mCanWrite = (open_flag & (O_WRONLY|O_RDWR)) ? true : false;
mCanSeek = S_ISREG(stat_buf.st_mode) ? true : false;
// seek to end of file if in append mode
if (mode == FileMode::Append)
{
seek_impl(0, SeekOrigin::End);
mIsAppendRestrictSeekCall = true;
}
}
int64_t tc::io::FileStream::length_impl()
{
int64_t length;
// get stat info on file
struct stat stat_buf;
if (fstat(mFileHandle->handle, &stat_buf) == -1)
{
throw tc::io::IOException(kClassName+"::length()", "Failed to check stream properties using fstat() (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
if (S_ISREG(stat_buf.st_mode))
{
length = stat_buf.st_size;
}
else
{
throw tc::NotSupportedException(kClassName+"::length()", "length() cannot be used with device-files or pipes");
}
return length;
}
size_t tc::io::FileStream::read_impl(byte_t* ptr, size_t count)
{
int64_t read_len = ::read(mFileHandle->handle, ptr, count);
// handle error
if (read_len == -1)
{
switch (errno)
{
case (EINVAL):
throw tc::ArgumentOutOfRangeException(kClassName+"::read()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EFAULT):
throw tc::AccessViolationException(kClassName+"::read()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EISDIR):
case (EBADF):
case (EAGAIN):
case (EINTR):
case (EIO):
default:
throw tc::io::IOException(kClassName+"::read()", "Failed to read from stream (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
return size_t(read_len);
}
size_t tc::io::FileStream::write_impl(const byte_t* ptr, size_t count)
{
int64_t write_len = ::write(mFileHandle->handle, ptr, count);
// handle error
if (write_len == -1)
{
switch (errno)
{
case (EINVAL):
throw tc::ArgumentOutOfRangeException(kClassName+"::write()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EFAULT):
throw tc::AccessViolationException(kClassName+"::write()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EFBIG):
case (EAGAIN):
case (EDESTADDRREQ):
case (EDQUOT):
case (EINTR):
case (EIO):
case (ENOSPC):
case (EPERM):
case (EPIPE):
default:
throw tc::io::IOException(kClassName+"::write()", "Failed to write to stream (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
return size_t(write_len);
}
int64_t tc::io::FileStream::seek_impl(int64_t offset, SeekOrigin origin)
{
int seek_flag = 0;
switch(origin)
{
case (SeekOrigin::Begin):
seek_flag = SEEK_SET;
break;
case (SeekOrigin::Current):
seek_flag = SEEK_CUR;
break;
case (SeekOrigin::End):
seek_flag = SEEK_END;
break;
default:
throw tc::ArgumentOutOfRangeException(kClassName+"::seek()", "Unknown SeekOrigin value");
}
#ifdef _LARGEFILE64_SOURCE
int64_t fpos = lseek64(mFileHandle->handle, offset, seek_flag);
#else
int64_t fpos = lseek(mFileHandle->handle, offset, seek_flag);
#endif
// handle error
if (fpos == -1)
{
switch (errno)
{
case (EINVAL):
throw tc::ArgumentOutOfRangeException(kClassName+"::seek()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EOVERFLOW):
throw tc::OverflowException(kClassName+"::seek()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EBADF):
case (ESPIPE):
case (ENXIO):
default:
throw tc::io::IOException(kClassName+"::seek()", "Failed to set stream position (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
return fpos;
}
void tc::io::FileStream::setLength_impl(int64_t length)
{
#ifdef _LARGEFILE64_SOURCE
int trun_res = ftruncate64(mFileHandle->handle, length);
#else
int trun_res = ftruncate(mFileHandle->handle, length);
#endif
if (trun_res == -1)
{
switch (errno)
{
case (EINTR):
case (EINVAL):
case (EFBIG):
case (EIO):
case (EBADF):
default:
throw tc::io::IOException(kClassName+"::seek()", "Failed to set stream position (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
}
void tc::io::FileStream::flush_impl()
{
// open/read/write are non-buffered
}
#endif
@@ -1,40 +0,0 @@
#include <tc/io/IOUtil.h>
int64_t tc::io::IOUtil::castSizeToInt64(size_t size)
{
if (std::numeric_limits<size_t>::digits > std::numeric_limits<int64_t>::digits)
size = std::min<size_t>(size, size_t(std::numeric_limits<int64_t>::max()));
return int64_t(size);
}
size_t tc::io::IOUtil::castInt64ToSize(int64_t length)
{
if (length < 0)
return 0;
if (std::numeric_limits<size_t>::digits < std::numeric_limits<int64_t>::digits)
length = std::min<int64_t>(length, int64_t(std::numeric_limits<size_t>::max()));
return size_t(length);
}
size_t tc::io::IOUtil::getAvailableSize(int64_t data_length, int64_t data_offset)
{
if (data_length < 0 || data_offset < 0)
return 0;
int64_t readable_length = (data_offset < data_length) ? (data_length - data_offset) : 0;
return castInt64ToSize(readable_length);
}
size_t tc::io::IOUtil::getReadableCount(int64_t data_length, int64_t data_offset, size_t requested_read_count)
{
return std::min<size_t>(getAvailableSize(data_length, data_offset), requested_read_count);
}
size_t tc::io::IOUtil::getWritableCount(int64_t data_length, int64_t data_offset, size_t requested_write_count)
{
return getReadableCount(data_length, data_offset, requested_write_count);
}
@@ -1,419 +0,0 @@
#include <tc/io/LocalFileSystem.h>
#include <tc/io/FileStream.h>
#include <tc/PlatformErrorHandlingUtil.h>
#include <tc/Exception.h>
#include <tc/string.h>
#ifdef _WIN32
#include <direct.h>
#include <cstdlib>
#pragma warning(disable : 4065) // disable warning for switch case with only default case
#else
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#endif
const std::string tc::io::LocalFileSystem::kClassName = "tc::io::LocalFileSystem";
tc::io::LocalFileSystem::LocalFileSystem() :
mState(1 << tc::RESFLAG_READY)
{
}
tc::ResourceStatus tc::io::LocalFileSystem::state()
{
return mState;
}
void tc::io::LocalFileSystem::dispose()
{
mState = (1 << tc::RESFLAG_NOINIT);
}
void tc::io::LocalFileSystem::createFile(const tc::io::Path& path)
{
tc::io::FileStream file(path, FileMode::Create, FileAccess::Write);
}
void tc::io::LocalFileSystem::removeFile(const tc::io::Path& path)
{
#ifdef _WIN32
// convert Path to unicode string
std::u16string unicode_path = path.to_u16string(tc::io::Path::Format::Win32);
// delete file
if (DeleteFileW((LPCWSTR)unicode_path.c_str()) == false)
{
DWORD error = GetLastError();
switch (error)
{
default:
throw tc::io::IOException(kClassName+"::removeFile()", "Failed to remove file (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
#else
// convert Path to unicode string
std::string unicode_path = path.to_string(tc::io::Path::Format::POSIX);
if (unlink(unicode_path.c_str()) == -1)
{
switch (errno)
{
case (EACCES): // Search permission is denied for a component of the path prefix. -OR- Write permission is denied on the directory containing the link to be removed.
case (EROFS): // The named file resides on a read-only file system.
case (EPERM): // The named file is a directory and the effective user ID of the process is not the super-user. -OR- The directory containing the file is marked sticky, and neither the containing directory nor the file to be removed are owned by the effective user ID.
case (EBUSY): // The entry to be unlinked is the mount point for a mounted file system. -OR- The file named by the path argument cannot be unlinked because it is being used by the system or by another process.
throw tc::UnauthorisedAccessException(kClassName+"::removeFile()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENAMETOOLONG): // A component of a pathname exceeds {NAME_MAX} characters, or an entire path name exceeds {PATH_MAX} characters (possibly as a result of expanding a symlink).
throw tc::io::PathTooLongException(kClassName+"::removeFile()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENOENT): // The named file does not exist.
throw tc::io::FileNotFoundException(kClassName+"::removeFile()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENOTDIR): // A component of the path prefix is not a directory.
throw tc::io::DirectoryNotFoundException(kClassName+"::removeFile()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EFAULT): // Path points outside the process's allocated address space.
case (EIO): // An I/O error occurs while deleting the directory entry or deallocating the inode.
case (ELOOP): // Too many symbolic links are encountered in translating the pathname. This is taken to be indicative of a looping symbolic link.
default:
throw tc::io::IOException(kClassName+"::removeFile()", "Failed to remove file (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
#endif
}
void tc::io::LocalFileSystem::openFile(const tc::io::Path& path, tc::io::FileMode mode, tc::io::FileAccess access, std::shared_ptr<tc::io::IStream>& stream)
{
stream = std::shared_ptr<tc::io::FileStream>(new tc::io::FileStream(path, mode, access));
}
void tc::io::LocalFileSystem::createDirectory(const tc::io::Path& path)
{
#ifdef _WIN32
// convert Path to unicode string
std::u16string unicode_path = path.to_u16string(tc::io::Path::Format::Win32);
// create directory
if (CreateDirectoryW((LPCWSTR)unicode_path.c_str(), nullptr) == false && GetLastError() != ERROR_ALREADY_EXISTS)
{
DWORD error = GetLastError();
switch (error)
{
default:
throw tc::io::IOException(kClassName+"::createDirectory()", "Failed to create directory (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
#else
// convert Path to unicode string
std::string unicode_path = path.to_string(tc::io::Path::Format::POSIX);
if (mkdir(unicode_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1 && errno != EEXIST)
{
switch (errno)
{
case (EACCES): // Search permission is denied for a component of the path prefix. -OR- Write permission is denied for the parent directory.
case (EROFS): // The parent directory resides on a read-only file system.
throw tc::UnauthorisedAccessException(kClassName+"::createDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENOTDIR): // A component of the path prefix is not a directory.
case (ENOENT): // A component of the path prefix does not exist or path is an empty string.
throw tc::io::DirectoryNotFoundException(kClassName+"::removeFile()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENAMETOOLONG): // A component of a pathname exceeded {NAME_MAX} characters, or an entire path name exceeded {PATH_MAX} characters.
throw tc::io::PathTooLongException(kClassName+"::removeFile()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EISDIR): // The named file is the root directory.
case (EDQUOT): // The new directory cannot be created because the user's quota of disk blocks on the file system that will contain the directory has been exhausted. -OR- The user's quota of inodes on the file system on which the directory is being created has been exhausted.
//case (EEXIST): // The named file exists
case (EFAULT): // Path points outside the process's allocated address space.
case (EIO): // An I/O error occurred while reading from or writing to the file system. -OR- An I/O error occurred while making the directory entry or allocating the inode.
case (ELOOP): // Too many symbolic links were encountered in translating the pathname. This is taken to be indicative of a looping symbolic link.
case (EMLINK): // The parent directory already has {LINK_MAX} links.
case (ENOSPC): // The new directory cannot be created because there is no space left on the file system that would contain it. -OR- There are no free inodes on the file system on which the directory is being created.
default:
throw tc::io::IOException(kClassName+"::createDirectory()", "Failed to create directory (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
#endif
}
void tc::io::LocalFileSystem::removeDirectory(const tc::io::Path& path)
{
#ifdef _WIN32
// convert Path to unicode string
std::u16string unicode_path = path.to_u16string(tc::io::Path::Format::Win32);
if (RemoveDirectoryW((wchar_t*)unicode_path.c_str()) == false)
{
DWORD error = GetLastError();
switch (error)
{
case (ERROR_DIR_NOT_EMPTY):
case (ERROR_DIRECTORY):
default:
throw tc::io::IOException(kClassName+"::removeDirectory()", "Failed to remove directory (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
#else
// convert Path to unicode string
std::string unicode_path = path.to_string(tc::io::Path::Format::POSIX);
if (rmdir(unicode_path.c_str()) == -1)
{
switch (errno)
{
case (EACCES): // Search permission is denied for a component of the path prefix. -OR- Write permission is denied on the directory containing the link to be removed.
case (EROFS): // The directory entry to be removed resides on a read-only file system.
case (EPERM): // The directory containing the directory to be removed is marked sticky, and neither the containing directory nor the directory to be removed are owned by the effective user ID.
case (EBUSY): // The directory to be removed is the mount point for a mounted file system.
throw tc::UnauthorisedAccessException(kClassName+"::removeDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENAMETOOLONG):
throw tc::io::PathTooLongException(kClassName+"::removeDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENOENT): // The named directory does not exist.
case (ENOTDIR): // A component of the path prefix is not a directory.
throw tc::io::DirectoryNotFoundException(kClassName+"::removeDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENOTEMPTY): // The named directory contains files other than `.' and `..' in it.
throw tc::io::DirectoryNotEmptyException(kClassName+"::removeDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EFAULT): // Path points outside the process's allocated address space.
case (EIO): // An I/O error occurred while reading from or writing to the file system.
case (ELOOP): // Too many symbolic links are encountered in translating the pathname. This is taken to be indicative of a looping symbolic link.
default:
throw tc::io::IOException(kClassName+"::removeDirectory()", "Failed to remove directory (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
#endif
}
void tc::io::LocalFileSystem::getWorkingDirectory(tc::io::Path& path)
{
#ifdef _WIN32
std::shared_ptr<char16_t> raw_char16_path(new char16_t[MAX_PATH]);
// get current directory
if (GetCurrentDirectoryW(MAX_PATH, (LPWSTR)(raw_char16_path.get())) == false)
{
DWORD error = GetLastError();
switch (error)
{
default:
throw tc::io::IOException(kClassName+"::getWorkingDirectory()", "Failed to get current working directory (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
path = Path(raw_char16_path.get());
#else
setWorkingDirectory(Path("."));
std::shared_ptr<char> raw_current_working_directory(new char[PATH_MAX]);
if (getcwd(raw_current_working_directory.get(), PATH_MAX) == nullptr)
{
switch (errno)
{
case (EACCES): // Read or search permission was denied for a component of the pathname. This is only checked in limited cases, depending on implementation details.
throw tc::UnauthorisedAccessException(kClassName+"::getWorkingDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EINVAL): // The size argument is zero.
case (ENOENT): // A component of the pathname no longer exists.
case (ENOMEM): // Insufficient memory is available.
case (ERANGE): // The size argument is greater than zero but smaller than the length of the pathname plus 1.
default:
throw tc::io::IOException(kClassName+"::getWorkingDirectory()", "Failed to get current working directory (getcwd) (" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
path = Path(raw_current_working_directory.get());
#endif
}
void tc::io::LocalFileSystem::setWorkingDirectory(const tc::io::Path& path)
{
#ifdef _WIN32
// convert Path to unicode string
std::u16string unicode_path = path.to_u16string(tc::io::Path::Format::Win32);
// delete file
if (SetCurrentDirectoryW((LPCWSTR)unicode_path.c_str()) == false)
{
DWORD error = GetLastError();
switch (error)
{
default:
throw tc::io::IOException(kClassName+"::setWorkingDirectory()", "Failed to set current working directory (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
#else
// convert Path to unicode string
std::string unicode_path = path.to_string(tc::io::Path::Format::POSIX);
// get full path to directory
if (chdir(unicode_path.c_str()) != 0)
{
switch (errno)
{
case (EACCES): // Search permission is denied for any component of the path name.
throw tc::UnauthorisedAccessException(kClassName+"::setWorkingDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENAMETOOLONG): // A component of a pathname exceeded {NAME_MAX} characters, or an entire path name exceeded {PATH_MAX} characters.
throw tc::io::PathTooLongException(kClassName+"::setWorkingDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENOENT): // The named directory does not exist.
case (ENOTDIR): // A component of the path prefix is not a directory.
throw tc::io::DirectoryNotFoundException(kClassName+"::setWorkingDirectory()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EFAULT): // Path points outside the process's allocated address space.
case (EIO): // An I/O error occurred while reading from or writing to the file system.
case (ELOOP): // Too many symbolic links were encountered in translating the pathname. This is taken to be indicative of a looping symbolic link.
default:
throw tc::io::IOException(kClassName+"::setWorkingDirectory()", "Failed to get directory info (chdir)(" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
#endif
}
void tc::io::LocalFileSystem::getDirectoryListing(const tc::io::Path& path, sDirectoryListing& info)
{
std::vector<std::string> child_dir_name_list;
std::vector<std::string> child_file_name_list;
Path current_directory_path;
#ifdef _WIN32
Path wildcard_path = path + tc::io::Path("*");
// convert Path to unicode string
std::u16string unicode_path = wildcard_path.to_u16string(tc::io::Path::Format::Win32);
HANDLE dir_handle = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW dir_entry;
dir_handle = FindFirstFileW((LPCWSTR)unicode_path.c_str(), &dir_entry);
if (dir_handle == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
switch (error)
{
default:
throw tc::io::IOException(kClassName+"::getDirectoryListing()", "Failed to open directory (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
do {
std::string utf8_name;
tc::string::TranscodeUtil::UTF16ToUTF8((char16_t*)dir_entry.cFileName, utf8_name);
if (dir_entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
child_dir_name_list.push_back(utf8_name);
}
else
{
child_file_name_list.push_back(utf8_name);
}
} while (FindNextFileW(dir_handle, &dir_entry) != 0);
// throw error where GetLastError() isn't just that there were no more files
if (GetLastError() != ERROR_NO_MORE_FILES)
{
FindClose(dir_handle);
DWORD error = GetLastError();
switch (error)
{
default:
throw tc::io::IOException(kClassName+"::getDirectoryListing()", "Failed to open directory (" + PlatformErrorHandlingUtil::GetLastErrorString(error) + ")");
}
}
FindClose(dir_handle);
// save current dir for later
Path prev_current_dir;
getWorkingDirectory(prev_current_dir);
// change the directory
setWorkingDirectory(path);
// save the path
getWorkingDirectory(current_directory_path);
// restore current directory
setWorkingDirectory(prev_current_dir);
#else
// convert Path to unicode string
std::string unicode_path = path.to_string(tc::io::Path::Format::POSIX);
// open directory
DIR *dp;
dp = opendir(unicode_path.c_str());
if (dp == nullptr)
{
switch (errno)
{
case (EACCES): // Permission denied.
throw tc::UnauthorisedAccessException(kClassName+"::getDirectoryListing()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (ENOTDIR): // A component of the path prefix is not a directory. // name is not a directory.
case (ENOENT): // Directory does not exist, or name is an empty string.
throw tc::io::DirectoryNotFoundException(kClassName+"::getDirectoryListing()", PlatformErrorHandlingUtil::GetGnuErrorNumString(errno));
case (EBADF): // fd is not a valid file descriptor open for reading.
case (EMFILE):
case (ENFILE):
case (ENOMEM):
default:
throw tc::io::IOException(kClassName+"::getDirectoryListing()", "Failed to get directory info (opendir)(" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
// get file and directory names
child_dir_name_list.clear();
child_file_name_list.clear();
// since errno can be set by external sources it will be cleared, since the conditions for checking errno being set aren't specific to failure
errno = 0;
for (struct dirent *ep = readdir(dp); ep != nullptr && errno == 0; ep = readdir(dp))
{
if (ep->d_type == DT_DIR)
{
child_dir_name_list.push_back(std::string(ep->d_name));
}
else if (ep->d_type == DT_REG)
{
child_file_name_list.push_back(std::string(ep->d_name));
}
}
// throw an error if necessary
if (errno != 0)
{
switch (errno)
{
case (EBADF): // fd is not a valid file descriptor open for reading.
case (EIO): // An I/O error occurred while reading from or writing to the file system.
default:
throw tc::io::IOException(kClassName+"::getDirectoryListing()", "Failed to get directory info (readdir)(" + PlatformErrorHandlingUtil::GetGnuErrorNumString(errno) + ")");
}
}
// close dp
closedir(dp);
// save current dir for later
Path prev_current_dir;
getWorkingDirectory(prev_current_dir);
// change the directory
setWorkingDirectory(path);
// save the path
getWorkingDirectory(current_directory_path);
// restore current directory
setWorkingDirectory(prev_current_dir);
#endif
info.abs_path = current_directory_path;
info.dir_list = child_dir_name_list;
info.file_list = child_file_name_list;
}
#ifdef _WIN32
#pragma warning(default : 4065) // reenable warning for switch case with only default case
#endif
@@ -1,49 +0,0 @@
#include <tc/io/MemorySource.h>
#include <tc/io/IOUtil.h>
const std::string tc::io::MemorySource::kClassName = "tc::io::MemorySource";
tc::io::MemorySource::MemorySource() :
mData()
{
}
tc::io::MemorySource::MemorySource(const tc::ByteData& byte_data) :
mData(byte_data)
{
}
tc::io::MemorySource::MemorySource(tc::ByteData&& byte_data) :
mData(std::move(byte_data))
{
}
tc::io::MemorySource::MemorySource(const byte_t* data, size_t len) :
mData(data, len)
{
}
int64_t tc::io::MemorySource::length()
{
return int64_t(mData.size());
}
tc::ByteData tc::io::MemorySource::pullData(int64_t offset, size_t count)
{
size_t read_len = IOUtil::getReadableCount(this->length(), offset, count);
// if the read length is zero then return now.
if (read_len == 0)
return tc::ByteData();
tc::ByteData out(read_len);
memcpy(out.data(), mData.data() + offset, read_len);
return out;
}
@@ -1,155 +0,0 @@
#include <tc/io/MemoryStream.h>
#include <limits>
#include <tc/io/StreamUtil.h>
#include <tc/io/IOUtil.h>
const std::string tc::io::MemoryStream::kClassName = "tc::io::MemoryStream";
tc::io::MemoryStream::MemoryStream() :
MemoryStream(0)
{}
tc::io::MemoryStream::MemoryStream(size_t length) :
mData(),
mPosition(0)
{
setLength(length);
}
tc::io::MemoryStream::MemoryStream(const tc::ByteData& byte_data) :
mData(byte_data),
mPosition(0)
{
}
tc::io::MemoryStream::MemoryStream(tc::ByteData&& byte_data) :
mData(std::move(byte_data)),
mPosition(0)
{
}
tc::io::MemoryStream::MemoryStream(const byte_t* data, size_t len) :
mData(data, len),
mPosition(0)
{
}
bool tc::io::MemoryStream::canRead() const
{
return true;
}
bool tc::io::MemoryStream::canWrite() const
{
return true;
}
bool tc::io::MemoryStream::canSeek() const
{
return true;
}
int64_t tc::io::MemoryStream::length()
{
return mData.size();
}
int64_t tc::io::MemoryStream::position()
{
return mPosition;
}
size_t tc::io::MemoryStream::read(byte_t* ptr, size_t count)
{
if (ptr == nullptr)
{
throw tc::ArgumentNullException(kClassName+"::read()", "ptr is null.");
}
count = IOUtil::getReadableCount(IOUtil::castSizeToInt64(mData.size()), mPosition, count);
memcpy(ptr, mData.data() + mPosition, count);
mPosition += IOUtil::castSizeToInt64(count);
return count;
}
size_t tc::io::MemoryStream::write(const byte_t* ptr, size_t count)
{
if (ptr == nullptr)
{
throw tc::ArgumentNullException(kClassName+"::write()", "ptr is null.");
}
// check if the position is past the end of stream, enlarge stream in this case
if ((IOUtil::castInt64ToSize(mPosition) + count) > mData.size())
{
setLength(mPosition + IOUtil::castSizeToInt64(count));
}
count = IOUtil::getWritableCount(IOUtil::castSizeToInt64(mData.size()), mPosition, count);
memcpy(mData.data() + mPosition, ptr, count);
mPosition += IOUtil::castSizeToInt64(count);
return count;
}
int64_t tc::io::MemoryStream::seek(int64_t offset, SeekOrigin origin)
{
int64_t new_pos = StreamUtil::getSeekResult(offset, origin, mPosition, (int64_t)mData.size());
if (new_pos < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName+"::seek()", "New position is negative.");
}
mPosition = new_pos;
return mPosition;
}
void tc::io::MemoryStream::setLength(int64_t length)
{
// check length isn't too large (int64_t could be larger than size_t)
if (IOUtil::castInt64ToSize(length) > std::numeric_limits<size_t>::max())
{
throw tc::ArgumentOutOfRangeException(kClassName+"::setLength()", "Length greater than maxium possible length for MemoryStream");
}
// check length isn't negative
if (length < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName+"::setLength()", "Length is negative.");
}
// create new ByteData
ByteData data(IOUtil::castInt64ToSize(length));
// determine copy length (between old and new ByteData)
size_t copy_len = std::min<size_t>(data.size(), mData.size());
// copy from old to new ByteData
memcpy(data.data(), mData.data(), copy_len);
// re-assign mData (this frees the old mData)
mData = data;
// reduce position if shrunk
mPosition = std::min<int64_t>(mPosition, int64_t(mData.size()));
}
void tc::io::MemoryStream::flush()
{
// do nothing
}
void tc::io::MemoryStream::dispose()
{
mData = ByteData();
}
@@ -1,143 +0,0 @@
#include <tc/io/OverlayedSource.h>
#include <tc/io/IOUtil.h>
const std::string tc::io::OverlayedSource::kClassName = "tc::io::OverlayedSource";
tc::io::OverlayedSource::OverlayedSource() :
mBaseSource(),
mOverlaySourceInfos()
{
}
tc::io::OverlayedSource::OverlayedSource(const std::shared_ptr<tc::io::ISource>& base_source, const std::shared_ptr<tc::io::ISource>& overlay_source, int64_t offset, int64_t length) :
OverlayedSource(base_source, {OverlaySourceInfo{overlay_source, offset, length}})
{
}
tc::io::OverlayedSource::OverlayedSource(const std::shared_ptr<tc::io::ISource>& base_source, const std::vector<OverlaySourceInfo>& overlay_source_infos)
{
// throw exception if the base source is null
if (base_source == nullptr)
{
throw tc::ArgumentNullException(kClassName+"::OverlayedSource()", "base_source was null.");
}
// copy base source ptr
mBaseSource = base_source;
// check/import overlay sources
for (auto itr = overlay_source_infos.begin(); itr != overlay_source_infos.end(); itr++)
{
// skip regions with no length
if (itr->length == 0)
{
continue;
}
// throw exception if a overlay source is null
if (itr->overlay_source == nullptr)
{
throw tc::ArgumentNullException(kClassName+"::OverlayedSource()", "overlay_source was null.");
}
// throw exception if overly region offset is negative
if (itr->offset < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName+"::OverlayedSource()", "Invalid overlay region. Overlay offset is negative.");
}
// throw exception if the overlay region offset is beyond the length of the base source
if (itr->offset > mBaseSource->length())
{
throw tc::ArgumentOutOfRangeException(kClassName+"::OverlayedSource()", "Invalid overlay region. Overlay offset beyond length of base_source.");
}
// throw exception if the overlay region exceeds the length of the base source
if ((itr->offset + itr->length) > mBaseSource->length())
{
throw tc::ArgumentOutOfRangeException(kClassName+"::OverlayedSource()", "Invalid overlay region. Overlay region exceeds the length of base_source.");
}
// throw exception if the overlay region exceeds the length of the overlay source
if (itr->length > itr->overlay_source->length())
{
throw tc::ArgumentOutOfRangeException(kClassName+"::OverlayedSource()", "Invalid overlay region. Overlay region exceeds the length of overlay_source.");
}
// save overlay source info
mOverlaySourceInfos.push_back(*itr);
}
}
int64_t tc::io::OverlayedSource::length()
{
// return 0 if mBaseSource is null, otherwise deref the pointer and get the length
return mBaseSource == nullptr ? 0 : mBaseSource->length();
}
tc::ByteData tc::io::OverlayedSource::pullData(int64_t offset, size_t count)
{
// return empty byte_data if the base is empty
if (mBaseSource == nullptr)
return tc::ByteData();
size_t read_len = IOUtil::getReadableCount(this->length(), offset, count);
// if the read length is zero then return now.
if (read_len == 0)
return tc::ByteData();
// get base source byte_data, this will be overwritten with regions
tc::ByteData out = mBaseSource->pullData(offset, count);
// iterate thru the overlays
for (auto itr = mOverlaySourceInfos.begin(); itr != mOverlaySourceInfos.end(); itr++)
{
int64_t overlay_pull_offset = 0;
size_t overlay_pull_count = 0;
// skip overlay if the pullable count is 0
getOverlaySourcePullableRegion(offset, count, *itr, overlay_pull_offset, overlay_pull_count);
if (overlay_pull_count == 0)
{
continue;
}
// pull data from overlay
ByteData overlay_pull = itr->overlay_source->pullData(overlay_pull_offset, overlay_pull_count);
// adjust the outsize to be the minimum of the ByteData & attempted pull_count
overlay_pull_count = std::min<size_t>(overlay_pull.size(), overlay_pull_count);
// copy into out buffer
int64_t overlay_offset_in_out = (overlay_pull_offset + itr->offset) - offset;
memcpy(out.data() + overlay_offset_in_out, overlay_pull.data(), overlay_pull_count);
}
return out;
}
void tc::io::OverlayedSource::getOverlaySourcePullableRegion(int64_t base_pull_offset, size_t base_pull_count, const OverlaySourceInfo& overlay_info, int64_t& overlay_pull_offset, size_t& overlay_pull_count)
{
int64_t overlay_relative_start_offset = base_pull_offset - overlay_info.offset;
int64_t overlay_relative_end_offset = overlay_relative_start_offset + int64_t(base_pull_count);
// if the start offset > overlay length: then the data starts after the overlay ends
// if the end offset < 0: then the data ends before the overlay begins
if (overlay_relative_start_offset > overlay_info.length || overlay_relative_end_offset < 0)
{
overlay_pull_offset = 0;
overlay_pull_count = 0;
}
// otherwise some or all of the overlay can be used
else
{
// the offset must be reset to zero if it is negative
overlay_pull_offset = overlay_relative_start_offset > 0 ? overlay_relative_start_offset : 0;
// getReadableSize will cap the amount read if it exceeds the base_length
overlay_pull_count = IOUtil::getReadableCount(overlay_info.length, overlay_pull_offset, size_t(overlay_relative_end_offset - overlay_pull_offset));
}
}
@@ -1,34 +0,0 @@
#include <tc/io/PaddingSource.h>
#include <tc/io/IOUtil.h>
const std::string tc::io::PaddingSource::kClassName = "tc::io::PaddingSource";
tc::io::PaddingSource::PaddingSource() :
mSourceLength(0),
mPaddingByte(0)
{
}
tc::io::PaddingSource::PaddingSource(byte_t padding_byte, int64_t size) :
mSourceLength(size),
mPaddingByte(padding_byte)
{
if (size < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName, "length is negative");
}
}
int64_t tc::io::PaddingSource::length()
{
return mSourceLength;
}
tc::ByteData tc::io::PaddingSource::pullData(int64_t offset, size_t count)
{
tc::ByteData data(IOUtil::getReadableCount(mSourceLength, offset, count));
memset(data.data(), mPaddingByte, data.size());
return data;
}
-331
View File
@@ -1,331 +0,0 @@
#include <tc/io/Path.h>
#include <tc/string.h>
#include <tc/Exception.h>
#include <fmt/core.h>
#include <sstream>
#include <iostream>
#include <regex>
static const char kWindowsPathSeparator = '\\'; /**< Path separator used on Microsoft Windows based systems */
static const char kPosixPathSeparator = '/'; /**< Path separator used on POSIX based systems */
#ifdef _WIN32
static const char kNativePathSeparator = kWindowsPathSeparator; /**< Path separator for the native environment */
#else
static const char kNativePathSeparator = kPosixPathSeparator; /**< Path separator for the native environment */
#endif
const std::string tc::io::Path::kClassName = "tc::io::Path";
tc::io::Path::Path()
{}
tc::io::Path::Path(std::initializer_list<std::string> list) :
mUnicodePath(list)
{
}
tc::io::Path::Path(const std::string& path)
{
initializePath(path);
}
tc::io::Path::Path(const std::u16string& path)
{
std::string utf8_path;
string::TranscodeUtil::UTF16ToUTF8(path, utf8_path);
initializePath(utf8_path);
}
tc::io::Path::Path(const std::u32string& path)
{
std::string utf8_path;
string::TranscodeUtil::UTF32ToUTF8(path, utf8_path);
initializePath(utf8_path);
}
tc::io::Path tc::io::Path::operator+(const Path& other) const
{
Path new_path = *this;
new_path.appendPath(other.mUnicodePath);
return new_path;
}
void tc::io::Path::operator+=(const Path& other)
{
appendPath(other.mUnicodePath);
}
bool tc::io::Path::operator==(const Path& other) const
{
return mUnicodePath == other.mUnicodePath;
}
bool tc::io::Path::operator!=(const Path& other) const
{
return !(this->operator==(other));
}
bool tc::io::Path::operator<(const Path& other) const
{
int cmp_score = 0;
auto self_itr = this->begin();
auto other_itr = other.begin();
// in this loop for as long as both path has an itr, it'll compare them
for (; self_itr != this->end() && other_itr != other.end(); self_itr++, other_itr++)
{
cmp_score = self_itr->compare(*other_itr);
if (cmp_score != 0)
break;
}
// if one of the itrs isn't the end, then that one is "larger"
// it can't be both or the prior loop won't have ended
if (cmp_score == 0 && (self_itr != this->end() || other_itr != other.end()))
{
cmp_score = self_itr == this->end() ? -1 : 1;
}
return cmp_score < 0;
}
tc::io::Path::iterator tc::io::Path::begin()
{
return mUnicodePath.begin();
}
std::string& tc::io::Path::front()
{
return mUnicodePath.front();
}
const std::string& tc::io::Path::front() const
{
return mUnicodePath.front();
}
std::string& tc::io::Path::back()
{
return mUnicodePath.back();
}
const std::string& tc::io::Path::back() const
{
return mUnicodePath.back();
}
tc::io::Path::const_iterator tc::io::Path::begin() const
{
return mUnicodePath.begin();
}
tc::io::Path::iterator tc::io::Path::end()
{
return mUnicodePath.end();
}
tc::io::Path::const_iterator tc::io::Path::end() const
{
return mUnicodePath.end();
}
void tc::io::Path::pop_front()
{
mUnicodePath.pop_front();
}
void tc::io::Path::pop_back()
{
mUnicodePath.pop_back();
}
void tc::io::Path::push_front(const std::string& str)
{
mUnicodePath.push_front(str);
}
void tc::io::Path::push_back(const std::string& str)
{
mUnicodePath.push_back(str);
}
void tc::io::Path::clear()
{
mUnicodePath.clear();
}
size_t tc::io::Path::size() const
{
return mUnicodePath.size();
}
bool tc::io::Path::empty() const
{
return mUnicodePath.empty();
}
tc::io::Path tc::io::Path::subpath(size_t pos, size_t len) const
{
tc::io::Path out_path;
auto itr = begin();
size_t index = 0;
// while the out_path size is less than len and the iterator hasn't ended
while ( out_path.size() < len && itr != end() )
{
// provided the index >= pos save the element
if (index >= pos)
{
out_path.push_back(*itr);
}
itr++;
index++;
}
return out_path;
}
tc::io::Path tc::io::Path::subpath(const_iterator begin, const_iterator end) const
{
tc::io::Path out_path;
for (auto itr = begin; itr != end && itr != this->end(); itr++)
{
out_path.push_back(*itr);
}
return out_path;
}
std::string tc::io::Path::to_string(Format format) const
{
std::string path_str = "";
if (format == Path::Format::Native)
{
#ifdef _WIN32
format = Path::Format::Win32;
#else
format = Path::Format::POSIX;
#endif
}
std::string path_separator_str;
switch (format)
{
case (Path::Format::POSIX):
path_separator_str = fmt::format("{:c}", kPosixPathSeparator);
break;
case (Path::Format::Win32):
path_separator_str = fmt::format("{:c}", kWindowsPathSeparator);
break;
default:
throw tc::ArgumentException(kClassName, "Invalid Format type.");
}
// special case where the path has one element and its the root path
if (this->size() == 1)
{
// for POSIX style this is the empty string ("/")
if (format == Path::Format::POSIX && this->front() == "")
return path_separator_str;
// for Win32 style this is a drive letter followed by ':' e.g. ("C:\")
else if (format == Path::Format::Win32 && std::regex_match(this->front(), std::regex("^([A-Z,a-z]):")))
return fmt::format("{}{}", this->front(), path_separator_str);
}
for (const_iterator itr = this->begin(); itr != this->end(); itr++)
{
path_str += *itr;
// don't print path separator where it would be trailing character
if (itr != --(this->end()))
path_str += path_separator_str;
}
return path_str;
}
std::u16string tc::io::Path::to_u16string(Format format) const
{
std::string u8string = to_string(format);
std::u16string u16string;
// convert
string::TranscodeUtil::UTF8ToUTF16(u8string, u16string);
// return
return u16string;
}
std::u32string tc::io::Path::to_u32string(Format format) const
{
std::string u8string = to_string(format);
std::u32string u32string;
// convert
string::TranscodeUtil::UTF8ToUTF32(u8string, u32string);
// return
return u32string;
}
tc::io::Path::operator std::string() const
{
return to_string(Format::Native);
}
tc::io::Path::operator std::u16string() const
{
return to_u16string(Format::Native);
}
tc::io::Path::operator std::u32string() const
{
return to_u32string(Format::Native);
}
void tc::io::Path::initializePath(const std::string& src)
{
size_t windows_slash_count = 0;
size_t posix_slash_count = 0;
for (size_t i = 0; i < src.size(); i++)
{
if (src[i] == kWindowsPathSeparator)
windows_slash_count += 1;
else if (src[i] == kPosixPathSeparator)
posix_slash_count += 1;
}
if (windows_slash_count != 0 && posix_slash_count != 0)
{
throw tc::ArgumentException(kClassName, "Path literal has both forward ('/') and backward ('\\') path separators.");
}
char path_delimiter = kNativePathSeparator;
if (windows_slash_count > 0)
path_delimiter = kWindowsPathSeparator;
else if (posix_slash_count > 0)
path_delimiter = kPosixPathSeparator;
std::stringstream src_stream(src);
std::string element;
while (std::getline(src_stream, element, path_delimiter))
{
mUnicodePath.push_back(element);
}
}
void tc::io::Path::appendPath(const std::list<std::string>& other)
{
for (std::list<std::string>::const_iterator itr = other.begin(); itr != other.end(); itr++)
{
mUnicodePath.push_back(*itr);
}
}
@@ -1,12 +0,0 @@
#include <tc/io/PathUtil.h>
#include <tc/string.h>
void tc::io::PathUtil::pathToWindowsUTF16(const tc::io::Path& path, std::u16string& out)
{
out = path.to_u16string(tc::io::Path::Format::Win32);
}
void tc::io::PathUtil::pathToUnixUTF8(const tc::io::Path& path, std::string& out)
{
out = path.to_string(tc::io::Path::Format::POSIX);
}
@@ -1,54 +0,0 @@
#include <tc/io/StreamSink.h>
const std::string tc::io::StreamSink::kClassName = "tc::io::StreamSink";
tc::io::StreamSink::StreamSink() :
mBaseStream(nullptr)
{
}
tc::io::StreamSink::StreamSink(const std::shared_ptr<tc::io::IStream>& stream) :
mBaseStream(stream)
{
if (mBaseStream == nullptr)
{
throw tc::ArgumentNullException(kClassName, "The base stream is null.");
}
if (mBaseStream->canWrite() == false)
{
throw tc::NotSupportedException(kClassName, "The base stream does not support writing.");
}
if (mBaseStream->canSeek() == false)
{
throw tc::NotSupportedException(kClassName, "The base stream does not support seeking.");
}
}
int64_t tc::io::StreamSink::length()
{
return mBaseStream == nullptr ? 0 :mBaseStream->length();
}
void tc::io::StreamSink::setLength(int64_t length)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::setLength()", "The base stream was not initialized.");
}
mBaseStream->setLength(length);
}
size_t tc::io::StreamSink::pushData(const tc::ByteData& data, int64_t offset)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::pushData()", "The base stream was not initialized.");
}
mBaseStream->seek(offset, tc::io::SeekOrigin::Begin);
return mBaseStream->write(data.data(), data.size());
}
@@ -1,55 +0,0 @@
#include <tc/io/StreamSource.h>
#include <tc/io/IOUtil.h>
const std::string tc::io::StreamSource::kClassName = "tc::io::StreamSource";
tc::io::StreamSource::StreamSource() :
mBaseStream(nullptr)
{
}
tc::io::StreamSource::StreamSource(const std::shared_ptr<tc::io::IStream>& stream) :
mBaseStream(stream)
{
if (mBaseStream == nullptr)
{
throw tc::ArgumentNullException(kClassName, "The base stream is null.");
}
if (mBaseStream->canRead() == false)
{
throw tc::NotSupportedException(kClassName, "The base stream does not support reading.");
}
if (mBaseStream->canSeek() == false)
{
throw tc::NotSupportedException(kClassName, "The base stream does not support seeking.");
}
}
int64_t tc::io::StreamSource::length()
{
return mBaseStream == nullptr ? 0 : mBaseStream->length();
}
tc::ByteData tc::io::StreamSource::pullData(int64_t offset, size_t count)
{
// get readable count
size_t read_count = IOUtil::getReadableCount(this->length(), offset, count);
// return if nothing is to be read
if (read_count == 0)
{
return tc::ByteData();
}
// allocate ByteData
ByteData data(read_count);
// read from stream (note this will not be called if mBaseStream is null, as in that case read_count == 0, and this code won't be reached)
mBaseStream->seek(offset, tc::io::SeekOrigin::Begin);
mBaseStream->read(data.data(), data.size());
// return populated ByteData
return data;
}
@@ -1,22 +0,0 @@
#include <tc/io/StreamUtil.h>
int64_t tc::io::StreamUtil::getSeekResult(int64_t offset, tc::io::SeekOrigin origin, int64_t current_position, int64_t stream_length)
{
int64_t new_pos = 0;
switch (origin)
{
case (SeekOrigin::Begin):
new_pos = offset;
break;
case (SeekOrigin::Current):
new_pos = current_position + offset;
break;
case (SeekOrigin::End):
new_pos = stream_length + offset;
break;
default:
throw tc::ArgumentOutOfRangeException("Illegal value for origin.");
}
return new_pos;
}
@@ -1,216 +0,0 @@
#include <tc/io/SubFileSystem.h>
const std::string tc::io::SubFileSystem::kClassName = "tc::io::SubFileSystem";
tc::io::SubFileSystem::SubFileSystem() :
mBaseFileSystem(),
mBasePathResolver(),
mSubPathResolver()
{
}
tc::io::SubFileSystem::SubFileSystem(const std::shared_ptr<tc::io::IFileSystem>& file_system, const tc::io::Path& base_path) :
SubFileSystem()
{
// copy IFileSystem ptr
mBaseFileSystem = file_system;
if (mBaseFileSystem == nullptr)
{
throw tc::ArgumentNullException(kClassName, "file_system is null");
}
else if (mBaseFileSystem->state().test(RESFLAG_READY) == false)
{
throw tc::InvalidOperationException(kClassName, "file_system is not ready");
}
// save current path
tc::io::Path prev_canonical_base_path;
mBaseFileSystem->getWorkingDirectory(prev_canonical_base_path);
// get full path of root
tc::io::Path canonical_base_path;
mBaseFileSystem->setWorkingDirectory(base_path);
mBaseFileSystem->getWorkingDirectory(canonical_base_path);
// restore current path
mBaseFileSystem->setWorkingDirectory(prev_canonical_base_path);
// set state for path resolvers
mBasePathResolver.setCurrentDirectory(canonical_base_path);
mSubPathResolver.setCurrentDirectory(tc::io::Path("/"));
}
tc::ResourceStatus tc::io::SubFileSystem::state()
{
return mBaseFileSystem.get() ? mBaseFileSystem->state() : tc::ResourceStatus(1 << tc::RESFLAG_NOINIT);
}
void tc::io::SubFileSystem::dispose()
{
if (mBaseFileSystem.get() != nullptr)
mBaseFileSystem->dispose();
mBasePathResolver = tc::io::BasicPathResolver();
mSubPathResolver = tc::io::BasicPathResolver();
}
void tc::io::SubFileSystem::createFile(const tc::io::Path& path)
{
if (mBaseFileSystem == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::createFile()", "Failed to create file (no base file system)");
}
// convert sub filesystem path to real path
tc::io::Path real_path;
subPathToRealPath(path, real_path);
// create file
mBaseFileSystem->createFile(real_path);
}
void tc::io::SubFileSystem::removeFile(const tc::io::Path& path)
{
if (mBaseFileSystem == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::removeFile()", "Failed to remove file (no base file system)");
}
// convert sub filesystem path to real path
tc::io::Path real_path;
subPathToRealPath(path, real_path);
// delete file
mBaseFileSystem->removeFile(real_path);
}
void tc::io::SubFileSystem::openFile(const tc::io::Path& path, tc::io::FileMode mode, tc::io::FileAccess access, std::shared_ptr<tc::io::IStream>& stream)
{
if (mBaseFileSystem == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::openFile()", "Failed to open file (no base file system)");
}
// convert sub filesystem path to real path
tc::io::Path real_path;
subPathToRealPath(path, real_path);
// open file
return mBaseFileSystem->openFile(real_path, mode, access, stream);
}
void tc::io::SubFileSystem::createDirectory(const tc::io::Path& path)
{
if (mBaseFileSystem == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::createDirectory()", "Failed to create directory (no base file system)");
}
// convert sub filesystem path to real path
tc::io::Path real_path;
subPathToRealPath(path, real_path);
// create directory
mBaseFileSystem->createDirectory(real_path);
}
void tc::io::SubFileSystem::removeDirectory(const tc::io::Path& path)
{
if (mBaseFileSystem == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::removeDirectory()", "Failed to remove directory (no base file system)");
}
// convert sub filesystem path to real path
tc::io::Path real_path;
subPathToRealPath(path, real_path);
// remove directory
mBaseFileSystem->removeDirectory(real_path);
}
void tc::io::SubFileSystem::getWorkingDirectory(tc::io::Path& path)
{
if (mBaseFileSystem == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::getWorkingDirectory()", "Failed to get current working directory (no base file system)");
}
path = mSubPathResolver.getCurrentDirectory();
}
void tc::io::SubFileSystem::setWorkingDirectory(const tc::io::Path& path)
{
if (mBaseFileSystem == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::setWorkingDirectory()", "Failed to set current working directory (no base file system)");
}
// convert sub filesystem path to real path
tc::io::Path canonical_base_path;
subPathToRealPath(path, canonical_base_path);
// save previous basefs working directory path
tc::io::Path prev_canonical_base_path;
mBaseFileSystem->getWorkingDirectory(prev_canonical_base_path);
// set and get working directory path so that canonical_base_path is populated with the full real path
mBaseFileSystem->setWorkingDirectory(canonical_base_path);
mBaseFileSystem->getWorkingDirectory(canonical_base_path);
// restore previous basefs working directory path
mBaseFileSystem->setWorkingDirectory(prev_canonical_base_path);
// save current directory
tc::io::Path canonical_sub_path;
realPathToSubPath(canonical_base_path, canonical_sub_path);
mSubPathResolver.setCurrentDirectory(canonical_sub_path);
}
void tc::io::SubFileSystem::getDirectoryListing(const tc::io::Path& path, sDirectoryListing& info)
{
if (mBaseFileSystem == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::getDirectoryListing()", "Failed to get directory listing (no base file system)");
}
// convert sub filesystem path to real path
tc::io::Path canonical_base_path;
subPathToRealPath(path, canonical_base_path);
// get real directory info
tc::io::sDirectoryListing dir_info;
mBaseFileSystem->getDirectoryListing(canonical_base_path, dir_info);
// convert directory absolute path
tc::io::Path canonical_sub_path;
realPathToSubPath(dir_info.abs_path, canonical_sub_path);
// update info with sub filesystem path
dir_info.abs_path = canonical_sub_path;
// write object to output
info = dir_info;
}
void tc::io::SubFileSystem::subPathToRealPath(const tc::io::Path& sub_path, tc::io::Path& real_path)
{
// get canonical sub path
tc::io::Path canonical_sub_path = mSubPathResolver.resolveCanonicalPath(sub_path);
// get canonical base path
real_path = mBasePathResolver.resolveCanonicalPath(canonical_sub_path.subpath(1, tc::io::Path::npos));
}
void tc::io::SubFileSystem::realPathToSubPath(const tc::io::Path& real_path, tc::io::Path& sub_path)
{
tc::io::Path canonical_base_path = mBasePathResolver.getCurrentDirectory();
if (real_path.subpath(0, canonical_base_path.size()) != canonical_base_path)
{
throw tc::UnauthorisedAccessException(kClassName, "Sub filesystem escape detected");
}
sub_path = tc::io::Path("/") + real_path.subpath(canonical_base_path.size(), tc::io::Path::npos);
}
@@ -1,73 +0,0 @@
#include <tc/io/SubSink.h>
#include <tc/io/IOUtil.h>
const std::string tc::io::SubSink::kClassName = "tc::io::SubSink";
tc::io::SubSink::SubSink() :
mBaseSink(nullptr),
mBaseSinkOffset(0),
mSubSinkLength(0)
{
}
tc::io::SubSink::SubSink(const std::shared_ptr<tc::io::ISink>& sink, int64_t offset, int64_t length) :
SubSink()
{
mBaseSink = sink;
// validate arguments
if (mBaseSink == nullptr)
{
throw tc::ArgumentNullException(kClassName, "The base sink is null.");
}
if (offset < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName, "offset is negative");
}
if (length < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName, "length is negative");
}
int64_t base_length = mBaseSink->length();
// validate arguments against sink length
// sub sink length should not be greater than the base sink length
if (length > base_length)
{
throw tc::ArgumentOutOfRangeException(kClassName, "The sub sink length is greater than base sink length.");
}
// Base length - length is the maximum possible offset for the sub sink
if (offset > (base_length - length))
{
throw tc::ArgumentOutOfRangeException(kClassName, "The sub sink offset is greater than the maximum possible offset given the base sink length and sub sink length.");
}
// set class state
mBaseSinkOffset = offset;
mSubSinkLength = length;
}
int64_t tc::io::SubSink::length()
{
return mBaseSink == nullptr ? 0 : mSubSinkLength;
}
void tc::io::SubSink::setLength(int64_t length)
{
throw tc::NotImplementedException(kClassName+"::setLength()", "setLength is not implemented for SubSink.");
}
size_t tc::io::SubSink::pushData(const tc::ByteData& data, int64_t offset)
{
if (mBaseSink == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::pushData()", "Failed to push data (no base sink)");
}
auto new_data = tc::ByteData(data.data(), IOUtil::getWritableCount(mSubSinkLength, offset, data.size()));
return mBaseSink->pushData(new_data, mBaseSinkOffset + offset);
}
@@ -1,66 +0,0 @@
#include <tc/io/SubSource.h>
#include <tc/io/IOUtil.h>
const std::string tc::io::SubSource::kClassName = "tc::io::SubSource";
tc::io::SubSource::SubSource() :
mBaseSource(nullptr),
mBaseSourceOffset(0),
mSubSourceLength(0)
{
}
tc::io::SubSource::SubSource(const std::shared_ptr<tc::io::ISource>& source, int64_t offset, int64_t length) :
SubSource()
{
mBaseSource = source;
// validate arguments
if (mBaseSource == nullptr)
{
throw tc::ArgumentNullException(kClassName, "source is null");
}
if (offset < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName, "offset is negative");
}
if (length < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName, "length is negative");
}
int64_t base_length = mBaseSource->length();
// validate arguments against source length
// sub source length should not be greater than the base source length
if (length > base_length)
{
throw tc::ArgumentOutOfRangeException(kClassName, "sub source length is greater than base source length");
}
// Base length - length is the maximum possible offset for the sub source
if (offset > (base_length - length))
{
throw tc::ArgumentOutOfRangeException(kClassName, "sub source offset is greater than the maximum possible offset given the base source size and sub source size");
}
// set class state
mBaseSourceOffset = offset;
mSubSourceLength = length;
}
int64_t tc::io::SubSource::length()
{
return mBaseSource == nullptr ? 0 : mSubSourceLength;
}
tc::ByteData tc::io::SubSource::pullData(int64_t offset, size_t count)
{
size_t pull_count = IOUtil::getReadableCount(length(), offset, count);
if (pull_count == 0)
return tc::ByteData();
return mBaseSource->pullData(mBaseSourceOffset + offset, pull_count);
}
@@ -1,183 +0,0 @@
#include <tc/io/SubStream.h>
#include <tc/io/IOUtil.h>
#include <tc/io/StreamUtil.h>
#include <algorithm>
const std::string tc::io::SubStream::kClassName = "tc::io::SubStream";
tc::io::SubStream::SubStream() :
mBaseStream(),
mBaseStreamOffset(0),
mSubStreamLength(0),
mSubStreamPosition(0)
{}
tc::io::SubStream::SubStream(const std::shared_ptr<tc::io::IStream>& stream, int64_t offset, int64_t length) :
SubStream()
{
// copy stream
mBaseStream = stream;
// validate the stream exists
if (mBaseStream == nullptr)
{
throw tc::ArgumentNullException(kClassName, "stream is null");
}
// check if the stream supports seeking
if (mBaseStream->canSeek() == false)
{
tc::NotSupportedException(kClassName, "Streams that do not support seeking are not supported");
}
// validate arguments
if (offset < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName, "offset is negative");
}
if (length < 0)
{
throw tc::ArgumentOutOfRangeException(kClassName, "length is negative");
}
int64_t base_length = mBaseStream->length();
// validate arguments against stream length
// substream length should not be greater than the base stream length
if (length > base_length)
{
throw tc::ArgumentOutOfRangeException(kClassName, "SubStream length is greater than base stream length");
}
// Base length - length is the maximum possible offset for the substream
if (offset > (base_length - length))
{
throw tc::ArgumentOutOfRangeException(kClassName, "SubStream offset is greater than the maximum possible offset given the base stream size and SubStream size");
}
// set class state
mBaseStreamOffset = offset;
mSubStreamLength = length;
mSubStreamPosition = 0;
}
bool tc::io::SubStream::canRead() const
{
return mBaseStream == nullptr ? false : mBaseStream->canRead();
}
bool tc::io::SubStream::canWrite() const
{
return mBaseStream == nullptr ? false : mBaseStream->canWrite();
}
bool tc::io::SubStream::canSeek() const
{
return mBaseStream == nullptr ? false : mBaseStream->canSeek();
}
int64_t tc::io::SubStream::length()
{
return mBaseStream == nullptr ? 0 : mSubStreamLength;
}
int64_t tc::io::SubStream::position()
{
return mBaseStream == nullptr ? 0 : mSubStreamPosition;
}
size_t tc::io::SubStream::read(byte_t* ptr, size_t count)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::read()", "Failed to read from stream (stream is disposed)");
}
count = IOUtil::getReadableCount(mSubStreamLength, mSubStreamPosition, count);
// assert proper position in file
mBaseStream->seek(mBaseStreamOffset + mSubStreamPosition, SeekOrigin::Begin);
// read data
size_t data_read_size = mBaseStream->read(ptr, count);
// update sub stream position
seek(data_read_size, SeekOrigin::Current);
return data_read_size;
}
size_t tc::io::SubStream::write(const byte_t* ptr, size_t count)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::write()", "Failed to write to stream (stream is disposed)");
}
count = IOUtil::getWritableCount(mSubStreamLength, mSubStreamPosition, count);
// assert proper position in file
mBaseStream->seek(mBaseStreamOffset + mSubStreamPosition, SeekOrigin::Begin);
// write data
size_t data_written_size = mBaseStream->write(ptr, count);
// update sub stream position
seek(data_written_size, SeekOrigin::Current);
return data_written_size;
}
int64_t tc::io::SubStream::seek(int64_t offset, SeekOrigin origin)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::seek()", "Failed to set stream position (stream is disposed)");
}
mSubStreamPosition = StreamUtil::getSeekResult(offset, origin, mSubStreamPosition, mSubStreamLength);
if (mSubStreamPosition < 0)
{
throw tc::InvalidOperationException(kClassName+"::seek()", "Negative seek result determined");
}
return mSubStreamPosition;
}
void tc::io::SubStream::setLength(int64_t length)
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::setLength()", "Failed to set stream length (stream is disposed)");
}
throw tc::NotImplementedException(kClassName+"::setLength()", "setLength is not implemented for SubStream");
}
void tc::io::SubStream::flush()
{
if (mBaseStream == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::seek()", "Failed to flush stream (stream is disposed)");
}
mBaseStream->flush();
}
void tc::io::SubStream::dispose()
{
if (mBaseStream.get() != nullptr)
{
// dispose base stream
mBaseStream->dispose();
// release ptr
mBaseStream.reset();
}
// clear state
mBaseStreamOffset = 0;
mSubStreamLength = 0;
mSubStreamPosition = 0;
}
@@ -1,192 +0,0 @@
#include <tc/io/VirtualFileSystem.h>
const std::string tc::io::VirtualFileSystem::kClassName = "tc::io::VirtualFileSystem";
tc::io::VirtualFileSystem::VirtualFileSystem() :
mCurDir(nullptr),
mFsSnapshot(),
mPathResolver()
{
}
tc::io::VirtualFileSystem::VirtualFileSystem(const FileSystemSnapshot& fs_snapshot, const std::shared_ptr<tc::io::IPortablePathResolver>& path_resolver) :
VirtualFileSystem()
{
mFsSnapshot = fs_snapshot;
mPathResolver = path_resolver;
// Use default path resolver if none was provided
if (mPathResolver == nullptr)
{
mPathResolver = std::shared_ptr<tc::io::BasicPathResolver>(new tc::io::BasicPathResolver());
}
// get root directory
tc::io::Path canonical_root_path = mPathResolver->resolveCanonicalPath(tc::io::Path("/"));
auto root_itr = mFsSnapshot.dir_entry_path_map.find(canonical_root_path);
// if the path was not found in the map, throw exception
if (root_itr == mFsSnapshot.dir_entry_path_map.end())
{
throw tc::InvalidOperationException(kClassName, "Failed to located root directory");
}
// if the dir_entry index isn't valid, throw exception
if (root_itr->second >= mFsSnapshot.dir_entries.size())
{
throw tc::InvalidOperationException(kClassName, "Failed to located root directory");
}
mCurDir = &mFsSnapshot.dir_entries.at(root_itr->second);
}
tc::ResourceStatus tc::io::VirtualFileSystem::state()
{
return mCurDir == nullptr? tc::ResourceStatus(1 << tc::RESFLAG_NOINIT) : tc::ResourceStatus(1 << tc::RESFLAG_READY);
}
void tc::io::VirtualFileSystem::dispose()
{
mCurDir = nullptr;
mFsSnapshot.dir_entries.clear();
mFsSnapshot.file_entries.clear();
mFsSnapshot.dir_entry_path_map.clear();
mFsSnapshot.file_entry_path_map.clear();
mPathResolver.reset();
}
void tc::io::VirtualFileSystem::createFile(const tc::io::Path& path)
{
if (mCurDir == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::createFile()", "VirtualFileSystem not initialized");
}
throw tc::NotImplementedException(kClassName+"::createFile()", "createFile is not supported for VirtualFileSystem");
}
void tc::io::VirtualFileSystem::removeFile(const tc::io::Path& path)
{
if (mCurDir == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::removeFile()", "VirtualFileSystem not initialized");
}
throw tc::NotImplementedException(kClassName+"::removeFile()", "removeFile is not supported for VirtualFileSystem");
}
void tc::io::VirtualFileSystem::openFile(const tc::io::Path& path, tc::io::FileMode mode, tc::io::FileAccess access, std::shared_ptr<tc::io::IStream>& stream)
{
if (mCurDir == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::openFile()", "VirtualFileSystem not initialized");
}
tc::io::Path resolved_path = mPathResolver->resolveCanonicalPath(path);
if (mode != tc::io::FileMode::Open)
{
throw tc::NotSupportedException(kClassName+"::openFile()", "This file-system is read-only, only FileMode::Open is supported.");
}
if (access != tc::io::FileAccess::Read)
{
throw tc::NotSupportedException(kClassName+"::openFile()", "This file-system is read-only, only FileAccess::Read is supported.");
}
auto file_itr = mFsSnapshot.file_entry_path_map.find(resolved_path);
// if resolved_path does not exist in the map, throw exception
if (file_itr == mFsSnapshot.file_entry_path_map.end())
{
throw tc::io::FileNotFoundException(kClassName+"::openFile()", "File does not exist.");
}
// if the file_entry index isn't valid or leads to a null IStream pointer, throw exception
if (file_itr->second >= mFsSnapshot.file_entries.size() || mFsSnapshot.file_entries.at(file_itr->second).stream == nullptr)
{
throw tc::io::FileNotFoundException(kClassName+"::openFile()", "File does not exist.");
}
// if the stream has invalid properties, throw exception
if ( !(mFsSnapshot.file_entries.at(file_itr->second).stream->canRead() == true && mFsSnapshot.file_entries.at(file_itr->second).stream->canWrite() == false) )
{
throw tc::io::FileNotFoundException(kClassName+"::openFile()", "File does not exist.");
}
stream = mFsSnapshot.file_entries.at(file_itr->second).stream;
}
void tc::io::VirtualFileSystem::createDirectory(const tc::io::Path& path)
{
if (mCurDir == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::createDirectory()", "VirtualFileSystem not initialized");
}
throw tc::NotImplementedException(kClassName+"::createDirectory()", "createDirectory is not supported for VirtualFileSystem");
}
void tc::io::VirtualFileSystem::removeDirectory(const tc::io::Path& path)
{
if (mCurDir == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::removeDirectory()", "VirtualFileSystem not initialized");
}
throw tc::NotImplementedException(kClassName+"::removeDirectory()", "removeDirectory is not supported for VirtualFileSystem");
}
void tc::io::VirtualFileSystem::getWorkingDirectory(tc::io::Path& path)
{
if (mCurDir == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::getWorkingDirectory()", "VirtualFileSystem not initialized");
}
path = mCurDir->dir_listing.abs_path;
}
void tc::io::VirtualFileSystem::setWorkingDirectory(const tc::io::Path& path)
{
if (mCurDir == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::setWorkingDirectory()", "VirtualFileSystem not initialized");
}
tc::io::Path resolved_path = mPathResolver->resolveCanonicalPath(path);
auto dir_itr = mFsSnapshot.dir_entry_path_map.find(resolved_path);
// if the path was not found in the map, throw exception
if (dir_itr == mFsSnapshot.dir_entry_path_map.end())
{
throw tc::io::DirectoryNotFoundException(kClassName+"::setWorkingDirectory()", "Directory does not exist.");
}
// if the dir_entry index isn't valid, throw exception
if (dir_itr->second >= mFsSnapshot.dir_entries.size())
{
throw tc::io::DirectoryNotFoundException(kClassName+"::setWorkingDirectory()", "Directory does not exist.");
}
mCurDir = &mFsSnapshot.dir_entries.at(dir_itr->second);
mPathResolver->setCurrentDirectory(mCurDir->dir_listing.abs_path);
}
void tc::io::VirtualFileSystem::getDirectoryListing(const tc::io::Path& path, tc::io::sDirectoryListing& info)
{
if (mCurDir == nullptr)
{
throw tc::ObjectDisposedException(kClassName+"::getDirectoryListing()", "VirtualFileSystem not initialized");
}
tc::io::Path resolved_path = mPathResolver->resolveCanonicalPath(path);
auto dir_itr = mFsSnapshot.dir_entry_path_map.find(resolved_path);
// if the path was not found in the map, throw exception
if (dir_itr == mFsSnapshot.dir_entry_path_map.end())
{
throw tc::io::DirectoryNotFoundException(kClassName+"::getDirectoryListing()", "Directory does not exist.");
}
// if the dir_entry index isn't valid, throw exception
if (dir_itr->second >= mFsSnapshot.dir_entries.size())
{
throw tc::io::DirectoryNotFoundException(kClassName+"::getDirectoryListing()", "Directory does not exist.");
}
info = mFsSnapshot.dir_entries.at(dir_itr->second).dir_listing;
}
@@ -1,40 +0,0 @@
#include <tc/os/Environment.h>
#include <tc/string.h>
bool tc::os::getEnvVar(const std::string& name, std::string& value)
{
bool did_find_variable = false;
#ifdef _WIN32
// convert utf-8 to utf-16 for wide char functions
std::u16string utf16_name;
tc::string::TranscodeUtil::UTF8ToUTF16(name, utf16_name);
// get size of environment variable
size_t required_size = 0;
_wgetenv_s(&required_size, nullptr, 0, (wchar_t*)utf16_name.c_str());
// set output if variable was found
if (required_size != 0)
{
// get environment variable
std::shared_ptr<wchar_t> utf16_value(new wchar_t[required_size]);
_wgetenv_s(&required_size, utf16_value.get(), required_size, (wchar_t*)utf16_name.c_str());
// transcode back to utf-8
tc::string::TranscodeUtil::UTF16ToUTF8((char16_t*)utf16_value.get(), value);
did_find_variable = true;
}
#else
// get ptr to env variable
char* env_ptr = getenv(name.c_str());
// set output if variable was found
if (env_ptr != nullptr)
{
value = std::string(env_ptr);
did_find_variable = true;
}
#endif
return did_find_variable;
}
@@ -1,165 +0,0 @@
#include <tc/string/TranscodeUtil.h>
#include <tc/ArgumentException.h>
#include <tc/string/detail/utf8.h>
#include <tc/string/detail/utf16.h>
void tc::string::TranscodeUtil::UTF8ToUTF32(const std::string& src, std::u32string& dst)
{
size_t done = 0;
dst.clear();
for (size_t i = 0; i < src.length(); i += done)
{
// get number of leading high bits in first byte
uint8_t prefix = detail::get_utf8_prefix(src[i]);
if (prefix == 1 || prefix > 4) // 1 is reserved for trailer bytes
{
throw tc::ArgumentException("not a UTF-8 string");
}
// if there are no prefix bits, this is ASCII
if (prefix == 0)
{
dst.push_back(src[i]);
done = 1;
}
// otherwise this is a multibyte character
else
{
// there must be enough characters
if ((i + prefix) > src.length())
{
throw tc::ArgumentException("not a UTF-8 string");
}
char32_t uni = detail::get_utf8_data(prefix, src[i]);
for (uint8_t j = 1; j < prefix; j++)
{
if (detail::utf8_has_prefix(1, src[i + j]) == false)
{
throw tc::ArgumentException("not a UTF-8 string");
}
uni <<= 6;
uni |= detail::get_utf8_data(1, src[i + j]);
}
if (uni >= detail::kUtf16HighSurrogateStart && uni <= detail::kUtf16LowSurrogateEnd)
{
throw tc::ArgumentException("not a UTF-8 string");
}
if (uni > detail::kUtf16EncodeMax)
{
throw tc::ArgumentException("not a UTF-8 string");
}
dst.push_back(uni);
done = prefix;
}
}
}
void tc::string::TranscodeUtil::UTF16ToUTF32(const std::u16string& src, std::u32string& dst)
{
size_t done = 0;
dst.clear();
for (size_t i = 0; i < src.length(); i+=done)
{
// this isn't a utf16 reserved character, so just add to unicode string
if (src[i] < detail::kUtf16HighSurrogateStart || src[i] > detail::kUtf16LowSurrogateEnd)
{
dst.push_back(src[i]);
done = 1;
}
// otherwise we need to decode it
else
{
// check that the high surrogate char exists first
if (src[i] < detail::kUtf16HighSurrogateStart || src[i] > detail::kUtf16HighSurrogateEnd)
{
throw tc::ArgumentException("not a UTF-16 string");
}
// check that the low surrogate char exists next
if (i >= src.length() - 1 || src[i + 1] < detail::kUtf16LowSurrogateStart || src[i + 1] > detail::kUtf16LowSurrogateEnd)
{
throw tc::ArgumentException("not a UTF-16 string");
}
char32_t uni = ((src[i] & detail::kUtf16SurrogateMask) << detail::kUtf16SurrogateBits) | (src[i + 1] & detail::kUtf16SurrogateMask) | 0x10000;
dst.push_back(uni);
done = 2;
}
}
}
void tc::string::TranscodeUtil::UTF32ToUTF8(const std::u32string& src, std::string& dst)
{
dst.clear();
for (size_t i = 0; i < src.length(); i++)
{
if (src[i] <= detail::kUtf8AsciiEnd)
{
dst.push_back((char)src[i]);
}
else if (src[i] <= detail::kUtf82ByteEnd)
{
dst.push_back(detail::make_utf8(2, (uint8_t)(src[i] >> 6)));
dst.push_back(detail::make_utf8(1, (uint8_t)(src[i] >> 0)));
}
else if (src[i] <= detail::kUtf83ByteEnd)
{
dst.push_back(detail::make_utf8(3, (uint8_t)(src[i] >> 12)));
dst.push_back(detail::make_utf8(1, (uint8_t)(src[i] >> 6)));
dst.push_back(detail::make_utf8(1, (uint8_t)(src[i] >> 0)));
}
else if (src[i] <= detail::kUtf84ByteEnd)
{
dst.push_back(detail::make_utf8(4, (uint8_t)(src[i] >> 18)));
dst.push_back(detail::make_utf8(1, (uint8_t)(src[i] >> 12)));
dst.push_back(detail::make_utf8(1, (uint8_t)(src[i] >> 6)));
dst.push_back(detail::make_utf8(1, (uint8_t)(src[i] >> 0)));
}
else
{
throw tc::ArgumentException("not a UTF-16 string");
}
}
}
void tc::string::TranscodeUtil::UTF32ToUTF16(const std::u32string& src, std::u16string& dst)
{
dst.clear();
for (size_t i = 0; i < src.size(); i++)
{
char32_t uni = src[i];
if (uni < detail::kUtf16NonNativeStart)
{
dst.push_back((char16_t)uni);
}
else
{
uni -= detail::kUtf16NonNativeStart;
dst.push_back(((uni >> detail::kUtf16SurrogateBits) & detail::kUtf16SurrogateMask) + detail::kUtf16HighSurrogateStart);
dst.push_back((uni & detail::kUtf16SurrogateMask) + detail::kUtf16LowSurrogateStart);
}
}
}
void tc::string::TranscodeUtil::UTF8ToUTF16(const std::string& src, std::u16string& dst)
{
std::u32string unicode;
TranscodeUtil::UTF8ToUTF32(src, unicode);
TranscodeUtil::UTF32ToUTF16(unicode, dst);
}
void tc::string::TranscodeUtil::UTF16ToUTF8(const std::u16string& src, std::string& dst)
{
std::u32string unicode;
TranscodeUtil::UTF16ToUTF32(src, unicode);
TranscodeUtil::UTF32ToUTF8(unicode, dst);
}
-26
View File
@@ -1,26 +0,0 @@
#include <tc/types.h>
bool tc::is_size_t_not_64bit()
{
return uint64_t(std::numeric_limits<size_t>::max()) < std::numeric_limits<uint64_t>::max();
}
bool tc::is_size_t_too_large_for_int64_t(size_t val)
{
return uint64_t(std::numeric_limits<int64_t>::max()) < uint64_t(val);
}
bool tc::is_uint64_t_too_large_for_int64_t(uint64_t val)
{
return uint64_t(std::numeric_limits<int64_t>::max()) < val;
}
bool tc::is_int64_t_too_large_for_size_t(int64_t val)
{
return uint64_t(std::numeric_limits<size_t>::max()) < uint64_t(val) || val < 0;
}
bool tc::is_uint64_t_too_large_for_size_t(uint64_t val)
{
return uint64_t(std::numeric_limits<size_t>::max()) < val;
}