diff options
Diffstat (limited to 'core/streams.cc')
-rw-r--r-- | core/streams.cc | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/core/streams.cc b/core/streams.cc new file mode 100644 index 0000000..191197a --- /dev/null +++ b/core/streams.cc @@ -0,0 +1,491 @@ +/** + * Stream implementation. + */ + +#include "../runtime/crypto.h" +#include "objects.h" +#include "osutils.h" +#include "streams.h" + +/** + * AbstractStream + */ + +size_t AbstractStream::CopyFrom(AbstractStream &source, size_t count) +{ + size_t copied_size, n, nc, total; +#define BUF_SIZE 4096 /* Let's use page size */ + uint8_t buf[BUF_SIZE]; + + total = 0; /* Total copied */ + for (n = 0; n < count; n += BUF_SIZE) { + nc = BUF_SIZE; /* Number of bytes to copy */ + if (count - n < BUF_SIZE) + nc = count - n; + copied_size = source.Read(buf, nc); + if (copied_size) + Write(buf, copied_size); + + total += copied_size; + if (nc != copied_size) + break; + } + Flush(); + return total; +} + +uint64_t AbstractStream::Tell() +{ + return Seek(0, soCurrent); +} + +uint64_t AbstractStream::Size() +{ + uint64_t pos = Tell(); + uint64_t size = Seek(0, soEnd); + /* Restore previous position */ + Seek(pos, soBeginning); + return size; +} + +/*static __inline bool IsCrLf(char c) +{ + return c == '\r' || c == '\n'; +}*/ + +/** + * MemoryStream + */ + +MemoryStream::MemoryStream(size_t /*buf_size_increment*/) + : pos_(0)/*, buf_size_inc_(buf_size_increment)*/ +{ +} + +size_t MemoryStream::Read(void *buffer, size_t size) +{ + if (pos_ + size > buf_.size()) + size = buf_.size() - pos_; + if (size) { + memcpy(buffer, &buf_[pos_], size); + pos_ += size; + } + return size; +} + +uint64_t MemoryStream::Resize(uint64_t new_size) +{ + buf_.resize(static_cast<size_t>(new_size)); + pos_ = buf_.size(); + return new_size; +} + +size_t MemoryStream::Write(const void *buffer, size_t size) +{ + if (size) { + if (pos_ + size > buf_.size()) + buf_.resize(pos_ + size); + + memcpy(&buf_[pos_], buffer, size); + pos_ += size; + } + return size; +} + +uint64_t MemoryStream::Seek(int64_t offset, SeekOrigin origin) +{ + intptr_t req_pos; + + req_pos = static_cast<intptr_t>(offset); + switch (origin) { + case soBeginning: + break; + case soCurrent: + req_pos += pos_; + break; + case soEnd: + req_pos += buf_.size(); + break; + default: + return -1; + } + pos_ = req_pos; + return pos_; +} + +/** + * MemoryStreamEnc + */ + +MemoryStreamEnc::MemoryStreamEnc(const void *buffer, size_t size, uint32_t key) + : MemoryStream(), key_(key) +{ + MemoryStream::Write(buffer, size); +} + +size_t MemoryStreamEnc::Read(void *buffer, size_t size) +{ + uint64_t pos = Seek(0, soCurrent); + size_t res = MemoryStream::Read(buffer, size); + for (size_t i = 0; i < res; i++) { + int p = static_cast<int>(pos + i); + reinterpret_cast<uint8_t *>(buffer)[i] ^= static_cast<uint8_t>(_rotl32(key_, p) + p); + } + return res; +} + +size_t MemoryStreamEnc::Write(const void *buffer, size_t size) +{ + size_t res; + if (size) { + uint64_t pos = Seek(0, soCurrent); + uint8_t *enc_buffer = new uint8_t[size]; + for (size_t i = 0; i < size; i++) { + int p = static_cast<int>(pos + i); + enc_buffer[i] = reinterpret_cast<const uint8_t *>(buffer)[i] ^ static_cast<uint8_t>(_rotl32(key_, p) + p); + } + res = MemoryStream::Write(enc_buffer, size); + delete [] enc_buffer; + } else { + res = MemoryStream::Write(buffer, size); + } + return res; +} + +/** + * ModuleStream + */ + +ModuleStream::ModuleStream() + : AbstractStream(), pos_(0), size_(0), base_address_(0), process_(0) +{ + +} + +ModuleStream::~ModuleStream() +{ + Close(); +} + +bool ModuleStream::Open(uint32_t process_id, HMODULE module) +{ + Close(); + + process_ = os::ProcessOpen(process_id); + if (!process_) + return false; + + MODULE_INFO module_info; + if (!os::GetModuleInformation(process_, module, &module_info, sizeof(module_info))) + return false; + + base_address_ = module_info.address; + size_ = module_info.size; + return true; +} + +void ModuleStream::Close() +{ + pos_ = 0; + size_ = 0; + base_address_ = NULL; + if (process_) { + os::ProcessClose(process_); + process_ = 0; + } +} + +size_t ModuleStream::Read(void *buffer, size_t size) +{ + size_t res = os::ProcessRead(process_, reinterpret_cast<uint8_t*>(base_address_) + pos_, buffer, size); + if (res != (size_t)-1) + pos_ += res; + return res; +} + +size_t ModuleStream::Write(const void *buffer, size_t size) +{ + size_t res = os::ProcessWrite(process_, reinterpret_cast<uint8_t*>(base_address_) + pos_, buffer, size); + if (res != (size_t)-1) + pos_ += res; + return res; +} + +uint64_t ModuleStream::Seek(int64_t offset, SeekOrigin origin) +{ + intptr_t req_pos; + + req_pos = static_cast<intptr_t>(offset); + switch (origin) { + case soBeginning: + break; + case soCurrent: + req_pos += pos_; + break; + case soEnd: + req_pos += size_; + break; + default: + return -1; + } + pos_ = req_pos; + return pos_; +} + +/** + * FileStream + */ + +FileStream::FileStream(size_t CACHE_ALLOC_SIZE /*= 0x10000*/) + : h_(INVALID_HANDLE_VALUE), cache_mode_(cmNone), CACHE_ALLOC_SIZE_(CACHE_ALLOC_SIZE), cache_pos_(0), cache_size_(0), cache_offset_(0) +{ + +} + +FileStream::~FileStream() +{ + Close(); +} + +bool FileStream::Open(const char *filename, int mode) +{ + Close(); + + h_ = os::FileCreate(filename, mode); + return (h_ != INVALID_HANDLE_VALUE); +} + +void FileStream::Close() +{ + FlushCache(); + + if (h_ != INVALID_HANDLE_VALUE) { + os::FileClose(h_); + h_ = INVALID_HANDLE_VALUE; + } +} + +uint8_t * FileStream::Cache() +{ + uint8_t *ret = cache_.get(); + if (ret == NULL) + { + ret = new uint8_t[CACHE_ALLOC_SIZE_]; + cache_.reset(ret); + } + return ret; +} + +void FileStream::FlushCache(bool need_seek) +{ + switch (cache_mode_) { + case cmRead: + if (need_seek && os::FileSeek(h_, cache_offset_ + cache_pos_, soBeginning) == (uint64_t)-1) + throw std::runtime_error("Runtime Error at Flush"); + break; + case cmWrite: + if (cache_pos_ && os::FileWrite(h_, Cache(), cache_pos_) != cache_pos_) + throw std::runtime_error("Runtime Error at Flush"); + break; + } + cache_mode_ = cmNone; + cache_size_ = 0; + cache_pos_ = 0; + cache_offset_ = 0; +} + +size_t FileStream::Read(void *buffer, size_t size) +{ + size_t add_size = 0; + if (cache_mode_ == cmRead) { + size_t cache_size = cache_size_ - cache_pos_; + if (size <= cache_size) { + memcpy(buffer, Cache() + cache_pos_, size); + cache_pos_ += size; + return size; + } + if (cache_size) { + memcpy(buffer, Cache() + cache_pos_, cache_size); + cache_pos_ += cache_size; + size -= cache_size; + add_size = cache_size; + buffer = static_cast<uint8_t*>(buffer) + cache_size; + } + } + FlushCache(); + + if (size < CACHE_ALLOC_SIZE_) { + cache_offset_ = os::FileSeek(h_, 0, soCurrent); + size_t cache_size = os::FileRead(h_, Cache(), CACHE_ALLOC_SIZE_); + // check error + if (cache_size == (size_t)-1) + return cache_size; + if (size > cache_size) + size = cache_size; + cache_mode_ = cmRead; + cache_size_ = cache_size; + memcpy(buffer, Cache(), size); + cache_pos_ = size; + return size + add_size; + } + + size_t res = os::FileRead(h_, buffer, size); + // check error + if (res == (size_t)-1) + return res; + return res + add_size; +} + +size_t FileStream::Write(const void *buffer, size_t size) +{ + size_t add_size = 0; + if (cache_mode_ == cmWrite) { + size_t cache_size = cache_size_ - cache_pos_; + if (size <= cache_size) { + memcpy(Cache() + cache_pos_, buffer, size); + cache_pos_ += size; + return size; + } + if (cache_size) { + memcpy(Cache() + cache_pos_, buffer, cache_size); + cache_pos_ += cache_size; + size -= cache_size; + add_size = cache_size; + buffer = static_cast<const uint8_t*>(buffer) + cache_size; + } + } + FlushCache(true); + + if (size < CACHE_ALLOC_SIZE_) { + cache_offset_ = os::FileSeek(h_, 0, soCurrent); + cache_mode_ = cmWrite; + cache_size_ = CACHE_ALLOC_SIZE_; + memcpy(Cache(), buffer, size); + cache_pos_ = size; + return size + add_size; + } + + size_t res = os::FileWrite(h_, buffer, size); + // check error + if (res == (size_t)-1) + return res; + return res + add_size; +} + +uint64_t FileStream::Seek(int64_t offset, SeekOrigin origin) +{ + if (cache_mode_ != cmNone) { + switch (origin) { + case soBeginning: + { + uint64_t pos = static_cast<uint64_t>(offset); + if (pos == cache_offset_ + cache_pos_) + return cache_offset_ + cache_pos_; + if (cache_mode_ == cmRead && pos >= cache_offset_ && pos <= cache_offset_ + cache_size_) { + cache_pos_ = static_cast<size_t>(pos - cache_offset_); + return cache_offset_ + cache_pos_; + } + } + break; + case soCurrent: + if (cache_mode_ == cmRead) { + if (offset + (int64_t)cache_pos_ >= 0 && offset + cache_pos_ <= cache_size_) { + cache_pos_ = static_cast<size_t>(offset + cache_pos_); + return cache_offset_ + cache_pos_; + } + offset -= cache_size_ - cache_pos_; + } + break; + } + FlushCache(); + } + + return os::FileSeek(h_, offset, origin); +} + +uint64_t FileStream::Resize(uint64_t new_size) +{ + uint64_t res = Seek(new_size, soBeginning); + FlushCache(true); + os::FileSetEnd(h_); + return res; +} + +bool FileStream::ReadLine(std::string &out_line) +{ + bool res = true; + out_line.clear(); + for (;;) { + char c; + if (Read(&c, sizeof(c)) == 0) { + res = !out_line.empty(); + break; + } + + if (c == '\n') { + break; + } else if (c == '\r') { + if (Read(&c, sizeof(c)) && c != '\n') + Seek(-1, soCurrent); + break; + } else { + out_line.push_back(c); + } + } + return res; +} + +std::string FileStream::ReadAll() +{ + std::string res; + size_t sz = static_cast<size_t>(Size()); + if (sz) { + res.resize(sz); + Read(&res[0], sz); + } + return res; +} + +/** + * Buffer + */ + +Buffer::Buffer(const uint8_t *memory) + : memory_(memory), position_(0) +{ + +} + +uint8_t Buffer::ReadByte() +{ + uint8_t res; + ReadBuff(&res, sizeof(res)); + return res; +} + +uint16_t Buffer::ReadWord() +{ + uint16_t res; + ReadBuff(&res, sizeof(res)); + return res; +} + +uint32_t Buffer::ReadDWord() +{ + uint32_t res; + ReadBuff(&res, sizeof(res)); + return res; +} + +uint64_t Buffer::ReadQWord() +{ + uint64_t res; + ReadBuff(&res, sizeof(res)); + return res; +} + +void Buffer::ReadBuff(void *buff, size_t size) +{ + memcpy(buff, &memory_[position_], size); + position_ += size; +}
\ No newline at end of file |