Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Copyright © 2015 Jeremy T. Hatcher All Rights Reserved
- */
- /*
- *
- * Synthetic Resource Archive(.sra)
- *
- * Format Specification Checklist
- *
- * HEADER FORMAT :
- *
- * ITEM idb : Identifiation bytes, 8 bytes
- * ITEM chks : Header checksum, 4 bytes
- * ITEM ver : Version number, 2 bytes
- * ITEM offs : Offset to first block, 4 bytes, rooted to file beginning
- * ITEM cd : Creation date, 4 bytes, unsigned UNIX time
- * ITEM len : File length, 4 bytes
- * ITEM arco : Archive count, 2 bytes
- *
- * Example :
- *
- * idb chks ver offs cd len arco
- * [00 00 00 00 00 00 00 00][00 00 00 00][00 00][00 00 00 00][00 00 00 00][00 00 00 00][00 00]
- *
- *
- *
- * BLOCK HEADER FORMAT :
- *
- * ITEM ver : Block format version number, 2 bytes
- * ITEM offs : Data offset, 2 bytes, rooted to file beginning
- * ITEM len : Block end, 4 bytes, rooted to file beginning
- * ITEM exl : Extension length, 1 byte
- * ITEM ext : Original format extension, exl bytes
- * ITEM nl : Name length, 1 byte, number of bytes for the name
- * ITEM name : Block name, nln bytes
- *
- * Example :
- *
- * ver offs len exl ext nl name
- * [00 00][00 00][00 00 00 00][00][00 .. 00][00][00 .. 00]
- *
- *
- *
- * STRUCTURE :
- *
- * [File Header][Block Header][Data...][Block Header][Data...][EOF Checksum]
- *
- */
- #include "SResArchive.h"
- #include <string>
- #include <stdint.h>
- #include <ctime>
- #include <algorithm>
- namespace SRA
- {
- #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
- namespace impl {
- typedef uint8_t byte;
- namespace bytes {
- namespace header {
- const int IDB = 8;
- const int CHKS = 4;
- const int VER = 2;
- const int OFFS = 4;
- const int CD = 4;
- const int LEN = 4;
- const int ARCO = 2;
- namespace offsets {
- const int oIDB = 0;
- const int oCHKS = IDB;
- const int oVER = oCHKS + CHKS;
- const int oOFFS = oVER + VER;
- const int oCD = oOFFS + OFFS;
- const int oLEN = oCD + CD;
- const int oARCO = oLEN + LEN;
- const int END_OF_HEADER = oARCO + ARCO;
- }
- }
- namespace block {
- const int VER = 2;
- const int OFFS = 2;
- const int LEN = 2;
- const int EXL = 1;
- const int NL = 1;
- namespace offsets {
- const int oVER = 0;
- const int oOFFS = oVER + VER;
- const int oLEN = oOFFS + OFFS;
- const int oEXL = oLEN + LEN;
- }
- }
- }
- namespace except {
- const char* MSG_ALREADY_OPEN = "File already opened";
- const char* MSG_NOT_OPEN = "No file opened";
- const char* MSG_NO_IDB_VERIF = "Unable to verify identification bytes";
- const char* MSG_CANT_OPEN = "Unable to open file";
- const char* MSG_ALREADY_WRITING = "Already writing to file";
- const char* MSG_NOT_WRITING = "Not currently writing to file";
- const char* MSG_IO_CONFLICT = "Cannot read and write to same file";
- const char* MSG_ALREADY_EXISTS = "File already exists";
- }
- const char IDB_STRING[bytes::header::IDB] = { 0x53, 0x52, 0x45, 0x53, 0x41, 0x52, 0x43, 0x48 };
- const unsigned short VER_NUMBER = 4;
- } // namespace impl
- namespace impl {
- static void func_error_if(bool condition, const char* msg, const char* file, int line)
- {
- if (condition) {
- std::string message = msg;
- message.append(std::string(" (") + file);
- message.append(std::string(" line: ") + std::to_string(line) + std::string(")"));
- throw SRAexcept(message.c_str());
- }
- }
- #define error_if(condition, message) \
- func_error_if(condition, message, __FILENAME__, __LINE__);
- // TODO: Endian checking
- static short buffer_to_short(char* buffer, int offset = 0) {
- short res = *(short*)buffer;
- return res;
- }
- static int buffer_to_int(char* buffer, int offset = 0) {
- int res = *(int*)buffer;
- return res;
- }
- static bool compare_bytes(const char* data1, const char* data2, int count) {
- return memcmp(data1, data2, count * sizeof(char)) == 0 ? true : false;
- }
- static bool verify_idb(char* buffer) {
- return compare_bytes(buffer, IDB_STRING, bytes::header::IDB);
- }
- static bool file_exists(const std::string path) {
- std::ifstream ifs(path);
- return ifs.good();
- }
- static unsigned int file_length(const std::string path) {
- std::ifstream ifs(path, std::ifstream::binary | std::ifstream::ate);
- error_if(!ifs.good(), except::MSG_CANT_OPEN);
- return (unsigned int)ifs.tellg();
- }
- static unsigned int file_length(std::ofstream& stream) {
- unsigned int put = (unsigned int)stream.tellp();
- stream.seekp(0, std::ofstream::end);
- unsigned int size = (unsigned int)stream.tellp();
- stream.seekp(0, put);
- return size;
- }
- int write_header_stub(std::ofstream& out)
- {
- out.seekp(0);
- using namespace bytes::header;
- int buffer_length = offsets::END_OF_HEADER + 31 & ~0x1F; // Add some padding to the buffer
- char* buffer = new char[buffer_length];
- memset(buffer, 0, buffer_length * sizeof(*buffer));
- memset(&buffer[offsets::END_OF_HEADER], 0x7F, buffer_length - offsets::END_OF_HEADER);
- out.write(buffer, buffer_length);
- delete[] buffer;
- return buffer_length; // end of buffer
- }
- void finalize_header(std::ofstream& out, int header_length, int num_blocks)
- {
- out.seekp(0);
- using namespace bytes::header;
- error_if(header_length < 32, except::MSG_NOT_WRITING);
- char* buffer = new char[header_length];
- memcpy(buffer, IDB_STRING, IDB * sizeof(char)); // IDB
- memset(&buffer[offsets::oCHKS], 'C', CHKS * sizeof(char)); // TODO: Checksum
- memcpy(&buffer[offsets::oVER], &VER_NUMBER, VER * sizeof(char)); // Version
- memcpy(&buffer[offsets::oOFFS], &header_length, OFFS * sizeof(char)); // Data offset
- unsigned int uts = (unsigned)time(nullptr);
- memcpy(&buffer[offsets::oCD], &uts, CD * sizeof(char)); // Timestamp
- unsigned int size = file_length(out);
- memcpy(&buffer[offsets::oLEN], &size, LEN * sizeof(char));
- memcpy(&buffer[offsets::oARCO], &num_blocks, ARCO * sizeof(char));
- out.write(buffer, offsets::END_OF_HEADER);
- delete[] buffer;
- }
- int write_block_header(std::ofstream& out)
- {
- return 0;
- }
- /*
- * IO_Device
- */
- void IO_Device::read_bytes_at_offset(char* buffer, int offset, int count)
- {
- error_if(!in.is_open(), except::MSG_NOT_OPEN);
- in.seekg(offset);
- in.read(buffer, count);
- }
- void IO_Device::erase_file_for_write()
- {
- close_streams();
- out.open(file_path, std::ofstream::binary | std::ofstream::trunc);
- }
- void IO_Device::close_streams()
- {
- if (in.is_open())
- in.close();
- if (out.is_open())
- out.close();
- }
- void IO_Device::open(std::string path)
- {
- using namespace bytes::header;
- error_if(in.is_open(), except::MSG_ALREADY_OPEN);
- in.open(path, std::ifstream::binary);
- error_if(!in.is_open(), except::MSG_CANT_OPEN);
- file_path = path;
- char buffer[IDB];
- in.read(buffer, IDB);
- error_if(!verify_idb(buffer), std::string(std::string(except::MSG_NO_IDB_VERIF) + std::string(" (") + std::string(buffer) + std::string(")")).c_str());
- }
- void IO_Device::close()
- {
- error_if(!in.is_open() && !out.is_open(), except::MSG_NOT_OPEN);
- file_path = "";
- close_streams();
- }
- void IO_Device::create(std::string path, bool overwrite)
- {
- if (overwrite == false) {
- error_if(file_exists(path), except::MSG_ALREADY_EXISTS);
- }
- if (file_exists(path)) {
- remove(path.c_str());
- }
- close_streams();
- out.open(path, std::ofstream::binary, std::ofstream::trunc);
- error_if(!out.is_open(), except::MSG_CANT_OPEN);
- file_path = path;
- }
- short IO_Device::get_version()
- {
- using namespace bytes::header;
- char buffer[2];
- read_bytes_at_offset(buffer, offsets::oVER, VER);
- return buffer_to_short(buffer);
- }
- int IO_Device::get_date()
- {
- using namespace bytes::header;
- char buffer[4];
- read_bytes_at_offset(buffer, offsets::oCD, CD);
- return buffer_to_int(buffer);
- }
- int IO_Device::get_size()
- {
- using namespace bytes::header;
- char buffer[4];
- read_bytes_at_offset(buffer, offsets::oLEN, LEN);
- return buffer_to_int(buffer);
- }
- short IO_Device::get_count()
- {
- using namespace bytes::header;
- char buffer[2];
- read_bytes_at_offset(buffer, offsets::oARCO, ARCO);
- return buffer_to_short(buffer);
- }
- void IO_Device::begin_writing()
- {
- error_if(writing, except::MSG_ALREADY_WRITING);
- using namespace bytes::header;
- writing = true;
- erase_file_for_write();
- error_if(!out.is_open(), except::MSG_CANT_OPEN);
- header_length = write_header_stub(out);
- }
- void IO_Device::write_block(std::string resource)
- {
- error_if(!writing, except::MSG_NOT_WRITING);
- error_if(!out.is_open(), except::MSG_NOT_OPEN);
- error_if(resource.compare(file_path) != 0, except::MSG_IO_CONFLICT);
- in.close();
- in.open(resource, std::ifstream::binary);
- }
- void IO_Device::end_writing()
- {
- error_if(!out.is_open(), except::MSG_NOT_OPEN);
- error_if(!writing, except::MSG_NOT_WRITING);
- using namespace bytes::header;
- finalize_header(out, header_length, blocks);
- writing = false;
- }
- } // namespace impl
- } // namespace sra
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement