refactor: Add StreamReader and StreamWriter classes

This commit is contained in:
Vsevolod Kremianskii 2020-11-07 23:40:17 +07:00
parent 74267e1123
commit a182063e2e
11 changed files with 500 additions and 1 deletions

View file

@ -48,19 +48,25 @@ add_definitions(-DBOOST_BIND_GLOBAL_PLACEHOLDERS)
## libsystem static library
set(SYSTEM_HEADERS
src/system/endianutil.h
src/system/jobs.h
src/system/log.h
src/system/pathutil.h
src/system/random.h
src/system/streamreader.h
src/system/streamutil.h
src/system/streamwriter.h
src/system/types.h)
set(SYSTEM_SOURCES
src/system/endianutil.cpp
src/system/jobs.cpp
src/system/log.cpp
src/system/pathutil.cpp
src/system/random.cpp
src/system/streamutil.cpp)
src/system/streamreader.cpp
src/system/streamutil.cpp
src/system/streamwriter.cpp)
add_library(libsystem STATIC ${SYSTEM_HEADERS} ${SYSTEM_SOURCES})
set_target_properties(libsystem PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
@ -388,6 +394,7 @@ set(GAME_HEADERS
src/game/room.h
src/game/rp/classes.h
src/game/rp/types.h
src/game/savfile.h
src/game/script/routines.h
src/game/script/util.h
src/game/types.h)
@ -462,6 +469,7 @@ set(GAME_SOURCES
src/game/portraits.cpp
src/game/room.cpp
src/game/rp/classes.cpp
src/game/savfile.cpp
src/game/script/routines.cpp
src/game/script/routines_common.cpp
src/game/script/routines_kotor.cpp

26
src/game/savfile.cpp Normal file
View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "savfile.h"
namespace reone {
namespace game {
} // namespace game
} // namespace reone

35
src/game/savfile.h Normal file
View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
namespace reone {
namespace game {
class SavFile {
public:
SavFile() = default;
private:
SavFile(const SavFile &) = delete;
SavFile &operator=(const SavFile &) = delete;
};
} // namespace game
} // namespace reone

93
src/system/endianutil.cpp Normal file
View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "endianutil.h"
#include <cstdint>
#include <cstring>
using namespace std;
namespace reone {
template <>
void swapBytes(uint16_t &val) {
val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
}
template <>
void swapBytes(uint32_t &val) {
val = ((val >> 24) & 0xff) |
(((val >> 16) & 0xff) << 8) |
(((val >> 8) & 0xff) << 16) |
((val & 0xff) << 24);
}
template <>
void swapBytes(uint64_t &val) {
val = ((val >> 56) & 0xff) |
(((val >> 48) & 0xff) << 8) |
(((val >> 40) & 0xff) << 16) |
(((val >> 32) & 0xff) << 24) |
(((val >> 24) & 0xff) << 32) |
(((val >> 16) & 0xff) << 40) |
(((val >> 8) & 0xff) << 48) |
((val & 0xff) << 56);
}
template <>
void swapBytes(int16_t &val) {
val = ((val >> 8) & 0xff) | ((val & 0xff) << 8);
}
template <>
void swapBytes(int32_t &val) {
val = ((val >> 24) & 0xff) |
(((val >> 16) & 0xff) << 8) |
(((val >> 8) & 0xff) << 16) |
((val & 0xff) << 24);
}
template <>
void swapBytes(int64_t &val) {
val = ((val >> 56) & 0xff) |
(((val >> 48) & 0xff) << 8) |
(((val >> 40) & 0xff) << 16) |
(((val >> 32) & 0xff) << 24) |
(((val >> 24) & 0xff) << 32) |
(((val >> 16) & 0xff) << 40) |
(((val >> 8) & 0xff) << 48) |
((val & 0xff) << 56);
}
template <>
void swapBytes(float &val) {
uint32_t uintVal;
memcpy(&uintVal, &val, 4);
swapBytes(uintVal);
memcpy(&val, &uintVal, 4);
}
template <>
void swapBytes(double &val) {
uint64_t uintVal;
memcpy(&uintVal, &val, 8);
swapBytes(uintVal);
memcpy(&val, &uintVal, 8);
}
} // namespace reone

25
src/system/endianutil.h Normal file
View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
namespace reone {
template <class T>
void swapBytes(T &val);
} // namespace reone

118
src/system/streamreader.cpp Normal file
View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "streamreader.h"
#include <sstream>
#include <stdexcept>
#include "endianutil.h"
using namespace std;
namespace reone {
StreamReader::StreamReader(const shared_ptr<istream> &stream, Endianess endianess) :
_stream(stream),
_endianess(endianess) {
if (!stream) {
throw invalid_argument("stream must not be null");
}
}
uint8_t StreamReader::getByte() {
uint8_t val;
_stream->read(reinterpret_cast<char *>(&val), 1);
return val;
}
uint16_t StreamReader::getUint16() {
uint16_t val;
_stream->read(reinterpret_cast<char *>(&val), 2);
return fixEndianess(val);
}
template <class T>
T StreamReader::fixEndianess(T val) {
if (!isSameEndianess()) {
swapBytes(val);
}
return val;
}
bool StreamReader::isSameEndianess() const {
return _endianess == Endianess::Little;
}
uint32_t StreamReader::getUint32() {
uint32_t val;
_stream->read(reinterpret_cast<char *>(&val), 4);
return fixEndianess(val);
}
uint64_t StreamReader::getUint64() {
uint64_t val;
_stream->read(reinterpret_cast<char *>(&val), 8);
return fixEndianess(val);
}
int16_t StreamReader::getInt16() {
int16_t val;
_stream->read(reinterpret_cast<char *>(&val), 2);
return fixEndianess(val);
}
int32_t StreamReader::getInt32() {
int32_t val;
_stream->read(reinterpret_cast<char *>(&val), 4);
return fixEndianess(val);
}
int64_t StreamReader::getInt64() {
int64_t val;
_stream->read(reinterpret_cast<char *>(&val), 8);
return fixEndianess(val);
}
float StreamReader::getFloat() {
float val;
_stream->read(reinterpret_cast<char *>(&val), 4);
return fixEndianess(val);
}
double StreamReader::getDouble() {
double val;
_stream->read(reinterpret_cast<char *>(&val), 8);
return fixEndianess(val);
}
string StreamReader::getCString() {
stringbuf ss;
_stream->get(ss, '\0');
_stream->seekg(1, ios::cur);
return ss.str();
}
string StreamReader::getString(int len) {
string val;
val.resize(len);
_stream->read(&val[0], len);
return move(val);
}
} // namespace reone

58
src/system/streamreader.h Normal file
View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <istream>
#include <memory>
#include <string>
#include "types.h"
namespace reone {
class StreamReader {
public:
StreamReader(const std::shared_ptr<std::istream> &stream, Endianess endianess = Endianess::Little);
uint8_t getByte();
uint16_t getUint16();
uint32_t getUint32();
uint64_t getUint64();
int16_t getInt16();
int32_t getInt32();
int64_t getInt64();
float getFloat();
double getDouble();
std::string getCString();
std::string getString(int len);
private:
std::shared_ptr<std::istream> _stream;
Endianess _endianess;
StreamReader(const StreamReader &) = delete;
StreamReader &operator=(const StreamReader &) = delete;
bool isSameEndianess() const;
template <class T>
T fixEndianess(T val);
};
} // namespace reone

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "streamwriter.h"
#include <stdexcept>
using namespace std;
namespace reone {
StreamWriter::StreamWriter(const shared_ptr<ostream> &stream, Endianess endianess) :
_stream(stream),
_endianess(endianess) {
if (!stream) {
throw invalid_argument("stream must not be null");
}
}
void StreamWriter::putByte(uint8_t val) {
}
} // namespace reone

42
src/system/streamwriter.h Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <memory>
#include <ostream>
#include "types.h"
namespace reone {
class StreamWriter {
public:
StreamWriter(const std::shared_ptr<std::ostream> &stream, Endianess endianess = Endianess::Little);
void putByte(uint8_t val);
private:
std::shared_ptr<std::ostream> _stream;
Endianess _endianess;
StreamWriter(const StreamWriter &) = delete;
StreamWriter &operator=(const StreamWriter &) = delete;
};
} // namespace reone

View file

@ -21,6 +21,11 @@
namespace reone {
enum class Endianess {
Little,
Big
};
typedef std::vector<char> ByteArray;
} // namespace reone

51
tests/streamreader.cpp Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#define BOOST_TEST_MODULE streamreader
#include <sstream>
#include <boost/test/included/unit_test.hpp>
#include "../src/system/streamreader.h"
using namespace std;
using namespace reone;
BOOST_AUTO_TEST_CASE(test_get_little_endian) {
shared_ptr<istringstream> stream(new istringstream(string("\x01" "\xe8\x03" "\xa0\x86\x01\x00" "\x00\xe4\x0b\x54\x02\x00\x00\x00" "\x60\x79\xfe\xff" "\x00\x00\x80\x3f" "abc\0defgh", 32)));
StreamReader reader(stream);
BOOST_TEST((reader.getByte() == 0x01));
BOOST_TEST((reader.getUint16() == 1000u));
BOOST_TEST((reader.getUint32() == 100000u));
BOOST_TEST((reader.getUint64() == 10000000000u));
BOOST_TEST((reader.getInt32() == -100000));
BOOST_TEST((reader.getFloat() == 1.0f));
BOOST_TEST((reader.getCString() == "abc"));
BOOST_TEST((reader.getString(3) == "def"));
}
BOOST_AUTO_TEST_CASE(test_get_big_endian) {
shared_ptr<istringstream> stream(new istringstream(string("\x03\xe8" "\x00\x01\x86\xa0" "\x00\x00\x00\x02\x54\x0b\xe4\x00" "\xff\xfe\x79\x60" "\x3f\x80\x00\x00", 22)));
StreamReader reader(stream, Endianess::Big);
BOOST_TEST((reader.getUint16() == 1000u));
BOOST_TEST((reader.getUint32() == 100000u));
BOOST_TEST((reader.getUint64() == 10000000000u));
BOOST_TEST((reader.getInt32() == -100000));
BOOST_TEST((reader.getFloat() == 1.0f));
}