Files
gMod/header/gMod_XorStream.h
T

80 lines
2.1 KiB
C++

#pragma once
#include <iostream>
#include <fstream>
class XORStream : public std::streambuf {
public:
XORStream(std::istream& stream) : innerStream(stream) {
if (!innerStream.seekg(0, std::ios::end).good() || !innerStream.seekg(0, std::ios::beg).good()) {
throw std::invalid_argument("Provided stream needs to have SEEK set to True");
}
originalStreamLength = innerStream.tellg();
innerStream.seekg(originalStreamLength - 1);
while (innerStream.tellg() > 0) {
const auto readByte = ReadByte();
if (readByte == 0) {
break;
}
innerStream.seekg(-2, std::ios::cur);
}
auto lastZeroPosition = innerStream.tellg() - 1;
innerStream.seekg(0);
length = lastZeroPosition;
setg(nullptr, nullptr, nullptr);
}
int_type underflow() override {
char_type buffer[2];
const auto bytesRead = innerStream.readsome(buffer, 2);
const auto startPosition = innerStream.tellg() - bytesRead;
for (int i = 0; i < bytesRead; i++) {
buffer[i] = XOR(buffer[i], i + startPosition);
}
auto bytesOverLength = startPosition + bytesRead - length;
for (int i = 0; i < bytesOverLength; i++) {
if (bytesRead - i - 1 >= 0) {
buffer[bytesRead - i - 1] = 0;
}
}
if (bytesRead > 0) {
setg(buffer, buffer, buffer + bytesRead);
return traits_type::to_int_type(buffer[0]);
}
return traits_type::eof();
}
private:
std::istream& innerStream;
long originalStreamLength;
long length;
char XOR(char b, long position) const {
if (position > originalStreamLength - 4) {
return b ^ TPF_XOREven;
}
return position % 2 == 0 ? b ^ TPF_XOREven : b ^ TPF_XOROdd;
}
char_type ReadByte() {
char_type byte;
if (innerStream.get(byte)) {
return XOR(byte, innerStream.tellg());
}
return traits_type::eof();
}
static const char TPF_XOROdd = 0x3F;
static const char TPF_XOREven = 0xA4;
};