Commit 55fecb5f authored by harha's avatar harha
Browse files

initial commit

parents
.vscode/
build/
cmake_minimum_required(VERSION 3.0)
project(ro-tool)
###############################################################################
## file globbing ##############################################################
###############################################################################
file(GLOB_RECURSE sources src/main/*.cpp src/main/*.h src/main/*.hpp)
file(GLOB_RECURSE sources_test src/test/*.cpp)
file(GLOB_RECURSE data data/main/*)
file(GLOB_RECURSE data_test data/test/*)
###############################################################################
## target definitions #########################################################
###############################################################################
add_executable(ro-tool ${sources} ${data})
target_compile_options(ro-tool PUBLIC -std=c++1y -Wall -Wfloat-conversion)
target_include_directories(ro-tool PUBLIC src/main)
file(COPY ${data} DESTINATION data)
###############################################################################
## dependencies ###############################################################
###############################################################################
#find_package(cpprestsdk REQUIRED)
#target_link_libraries(ro-tool PUBLIC
# cpprestsdk::cpprest
#)
###############################################################################
## testing ####################################################################
###############################################################################
find_package(GTest)
if(GTEST_FOUND)
add_executable(ro-tool-tests ${sources_test} ${sources} ${data_test})
target_compile_definitions(ro-tool-tests PUBLIC UNIT_TESTS)
set_target_properties(ro-tool PROPERTIES ENABLE_EXPORTS on)
target_link_libraries(ro-tool-tests PUBLIC
${GTEST_BOTH_LIBRARIES}
ro-tool
)
target_include_directories(ro-tool-tests PUBLIC
${GTEST_INCLUDE_DIRS}
)
file(COPY ${data_test} DESTINATION data_test)
install(DIRECTORY data_test DESTINATION ${CMAKE_SOURCE_DIR}/target)
endif()
###############################################################################
## packaging ##################################################################
###############################################################################
install(TARGETS ro-tool DESTINATION ${CMAKE_SOURCE_DIR}/target)
install(DIRECTORY data DESTINATION ${CMAKE_SOURCE_DIR}/target)
set(CPACK_PACKAGE_NAME "ro-tool")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_MONOLITHIC_INSTALL 1)
include(CPack)
# ro-tool
Open source tools for loading, parsing, verifying and modifying Ragnarok Online related file formats.
## build
- mkdir build
- cmake ../
- make
## run
- ./ro-tool
## run tests
Make sure you have GTest installed before building.
- ./ro-tool-tests
#include "fformat_gat.hpp"
#include <cstdio>
#include <cstring>
FFormatGAT::FFormatGAT(
const std::string & filePath
) :
m_filePath(filePath),
m_data(nullptr),
m_state(GAT_FILE_STATE_UNLOADED)
{
load();
printf("FFormatGAT::FFormatGAT() m_filePath: %s\n", m_filePath.c_str());
}
FFormatGAT::~FFormatGAT()
{
printf("FFormatGAT::~FFormatGAT()\n");
if (m_data != nullptr)
{
delete m_data->blocks;
delete m_data;
}
m_state = GAT_FILE_STATE_UNLOADED;
}
void FFormatGAT::setFilePath(const std::string & filePath)
{
m_filePath = filePath;
}
const std::string & FFormatGAT::getFilePath() const
{
return m_filePath;
}
const GATFile * FFormatGAT::getData() const
{
return m_data;
}
GATFileState_t FFormatGAT::getState() const
{
return m_state;
}
void FFormatGAT::load()
{
// open file in binary mode
FILE * file_ptr = fopen(m_filePath.c_str(), "rb");
// on error, inform about failure and return
if (file_ptr == NULL)
{
printf("FFormatGAT::load() fopen failed! File not loaded. errno: %d\n", errno);
m_state = GAT_FILE_STATE_INVALID_FILE;
return;
}
// get file size in bytes
fseek(file_ptr, 0, SEEK_END);
size_t file_size = static_cast<size_t>(ftell(file_ptr));
rewind(file_ptr);
// read file into a temp buffer
uint8_t * file_buf = new uint8_t[file_size];
fread(file_buf, file_size, 1, file_ptr);
fclose(file_ptr);
// parse file header
m_data = new GATFile;
m_data->blocks = nullptr;
memcpy(&m_data->magic[0], &file_buf[0], 6);
memcpy(&m_data->width, &file_buf[6], 4);
memcpy(&m_data->height, &file_buf[10], 4);
// verify file format and structure
bool file_valid = verify();
// on error, inform about failure and return
if (file_valid == false)
{
printf("FFormatGAT::load() verify failed! File not loaded.\n");
delete m_data;
delete file_buf;
return;
}
printf("FFormatGAT::load() width: %u, height: %u\n", m_data->width, m_data->height);
// parse file blocks
size_t file_offset = 14;
size_t block_index = 0;
size_t blocks_n = (file_size - file_offset) / 20;
printf("FFormatGAT::load() blocks_n: %zu\n", blocks_n);
m_data->blocks = new GATBlock[blocks_n];
while (file_offset < file_size)
{
GATBlock * block = &m_data->blocks[block_index];
// parse file block
memcpy(&block->h_ul, &file_buf[file_offset + 0], 4);
memcpy(&block->h_ur, &file_buf[file_offset + 4], 4);
memcpy(&block->h_ll, &file_buf[file_offset + 8], 4);
memcpy(&block->h_lr, &file_buf[file_offset + 12], 4);
memcpy(&block->type, &file_buf[file_offset + 16], 1);
memcpy(&block->unknown[0], &file_buf[file_offset + 17], 3);
// move to next block
block_index++;
file_offset += 20;
}
printf("FFormatGAT::load() parsed blocks_n: %zu\n", block_index);
// free temp buffer
delete file_buf;
// set file state to loaded
m_state = GAT_FILE_STATE_LOADED;
}
bool FFormatGAT::verify()
{
// check magic number
char * magic_num = new char[7];
magic_num[6] = '\0';
memcpy(magic_num, &m_data->magic[0], 6);
printf("FFormatGAT::verify() magic_num: %s\n", m_data->magic);
if (strcmp(magic_num, FFORMAT_GAT_FILE_MAGIC_NUM) != 0)
{
printf("FFormatGAT::verify() magic_num check failed!\n");
m_state = GAT_FILE_STATE_INVALID_MAGIC;
return false;
}
// free temp memory
delete magic_num;
return true;
}
#ifndef RO_TOOL_FFORMAT_GAT_H
#define RO_TOOL_FFORMAT_GAT_H
#include <cstdint>
#include <string>
#define FFORMAT_GAT_BLOCK_TYPE_MASK_WB 0b00000001
#define FFORMAT_GAT_BLOCK_TYPE_MASK_NWB 0b00000010
#define FFORMAT_GAT_BLOCK_TYPE_MASK_NWWNS 0b00000100
#define FFORMAT_GAT_BLOCK_TYPE_MASK_WW 0b00001000
#define FFORMAT_GAT_BLOCK_TYPE_MASK_NWWS 0b00010000
#define FFORMAT_GAT_BLOCK_TYPE_MASK_CS 0b00100000
#define FFORMAT_GAT_BLOCK_TYPE_MASK_CNS 0b01000000
typedef struct GATBlock
{
float h_ul; // 0 uppef-left
float h_ur; // 4 upper-right
float h_ll; // 8 lower-left
float h_lr; // 12 lower-right
uint8_t type; // 16 type (FFORMAT_GAT_BLOCK_TYPE_MASK_*)
uint8_t unknown[3]; // 17
} GATBlock;
#define FFORMAT_GAT_FILE_MAGIC_NUM "GRAT\x01\x02"
typedef struct GATFile
{
uint8_t magic[6]; // 0 "GRAT\x01\x02"
uint32_t width; // 6
uint32_t height; // 10
GATBlock * blocks; // 14
} GATFile;
enum GATFileState_t
{
GAT_FILE_STATE_UNLOADED = 0,
GAT_FILE_STATE_LOADED = 1,
GAT_FILE_STATE_INVALID_FILE = 2,
GAT_FILE_STATE_INVALID_MAGIC = 3
};
class FFormatGAT
{
public:
FFormatGAT(
const std::string & filePath
);
~FFormatGAT();
void setFilePath(const std::string & filePath);
const std::string & getFilePath() const;
const GATFile * getData() const;
GATFileState_t getState() const;
private:
void load();
bool verify();
std::string m_filePath;
GATFile * m_data;
GATFileState_t m_state;
};
#endif // RO_TOOL_FFORMAT_GAT_H
#include "main.hpp"
#include <iostream>
#ifdef UNIT_TESTS
#define MAIN not_main
#else
#define MAIN main
#endif
int MAIN(int argc, char * argv[]) {
return EXIT_SUCCESS;
}
#ifndef RO_TOOL_MAIN_H
#define RO_TOOL_MAIN_H
#endif // RO_TOOL_MAIN_H
#include <gtest/gtest.h>
#include <fformat_gat.hpp>
TEST(test_fformat_gat, gat_load_amatsu)
{
FFormatGAT file("./data_test/amatsu.gat");
ASSERT_EQ(file.getState(), GAT_FILE_STATE_LOADED);
}
TEST(test_fformat_gat, gat_load_einbroch)
{
FFormatGAT file("./data_test/einbroch.gat");
ASSERT_EQ(file.getState(), GAT_FILE_STATE_LOADED);
}
TEST(test_fformat_gat, gat_load_invalid_file_fails)
{
FFormatGAT file("./data_test/nonexistent.gat");
ASSERT_EQ(file.getState(), GAT_FILE_STATE_INVALID_FILE);
}
TEST(test_fformat_gat, gat_load_invalid_magic_fails)
{
FFormatGAT file("./data_test/invalid.gat");
ASSERT_EQ(file.getState(), GAT_FILE_STATE_INVALID_MAGIC);
}
#include <main.hpp>
#include <gtest/gtest.h>
TEST(gtest, gtest_works) {
ASSERT_TRUE(true);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment