Advertisement
Guest User

Untitled

a guest
Nov 27th, 2015
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.26 KB | None | 0 0
  1. /*
  2. * Copyright © 2015 Jeremy T. Hatcher All Rights Reserved
  3. */
  4.  
  5. /*
  6. *
  7. * Synthetic Resource Archive(.sra)
  8. *
  9. * Format Specification Checklist
  10. *
  11. * HEADER FORMAT :
  12. *
  13. * ITEM idb : Identifiation bytes, 8 bytes
  14. * ITEM chks : Header checksum, 4 bytes
  15. * ITEM ver : Version number, 2 bytes
  16. * ITEM offs : Offset to first block, 4 bytes, rooted to file beginning
  17. * ITEM cd : Creation date, 4 bytes, unsigned UNIX time
  18. * ITEM len : File length, 4 bytes
  19. * ITEM arco : Archive count, 2 bytes
  20. *
  21. * Example :
  22. *
  23. * idb                      chks         ver    offs         cd           len          arco
  24. * [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]
  25. *
  26. *
  27. *
  28. * BLOCK HEADER FORMAT :
  29. *
  30. * ITEM ver : Block format version number, 2 bytes
  31. * ITEM offs : Data offset, 2 bytes, rooted to file beginning
  32. * ITEM len : Block end, 4 bytes, rooted to file beginning
  33. * ITEM exl : Extension length, 1 byte
  34. * ITEM ext : Original format extension, exl bytes
  35. * ITEM nl : Name length, 1 byte, number of bytes for the name
  36. * ITEM name : Block name, nln bytes
  37. *
  38. * Example :
  39. *
  40. * ver    offs   len          exl ext       nl  name
  41. * [00 00][00 00][00 00 00 00][00][00 .. 00][00][00 .. 00]
  42. *
  43. *
  44. *
  45. * STRUCTURE :
  46. *
  47. * [File Header][Block Header][Data...][Block Header][Data...][EOF Checksum]
  48. *
  49. */
  50.  
  51. #include "SResArchive.h"
  52.  
  53. #include <string>
  54. #include <stdint.h>
  55. #include <ctime>
  56. #include <algorithm>
  57.  
  58. namespace SRA
  59. {
  60.  
  61. #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
  62.    
  63.     namespace impl {
  64.         typedef uint8_t byte;
  65.  
  66.         namespace bytes {
  67.             namespace header {
  68.                 const int IDB = 8;
  69.                 const int CHKS = 4;
  70.                 const int VER = 2;
  71.                 const int OFFS = 4;
  72.                 const int CD = 4;
  73.                 const int LEN = 4;
  74.                 const int ARCO = 2;
  75.  
  76.                 namespace offsets {
  77.                     const int oIDB = 0;
  78.                     const int oCHKS = IDB;
  79.                     const int oVER = oCHKS + CHKS;
  80.                     const int oOFFS = oVER + VER;
  81.                     const int oCD = oOFFS + OFFS;
  82.                     const int oLEN = oCD + CD;
  83.                     const int oARCO = oLEN + LEN;
  84.  
  85.                     const int END_OF_HEADER = oARCO + ARCO;
  86.                 }
  87.             }
  88.  
  89.             namespace block {
  90.                 const int VER = 2;
  91.                 const int OFFS = 2;
  92.                 const int LEN = 2;
  93.                 const int EXL = 1;
  94.                 const int NL = 1;
  95.  
  96.                 namespace offsets {
  97.                     const int oVER = 0;
  98.                     const int oOFFS = oVER + VER;
  99.                     const int oLEN = oOFFS + OFFS;
  100.                     const int oEXL = oLEN + LEN;
  101.                 }
  102.             }
  103.         }
  104.  
  105.         namespace except {
  106.             const char* MSG_ALREADY_OPEN = "File already opened";
  107.             const char* MSG_NOT_OPEN = "No file opened";
  108.             const char* MSG_NO_IDB_VERIF = "Unable to verify identification bytes";
  109.             const char* MSG_CANT_OPEN = "Unable to open file";
  110.             const char* MSG_ALREADY_WRITING = "Already writing to file";
  111.             const char* MSG_NOT_WRITING = "Not currently writing to file";
  112.             const char* MSG_IO_CONFLICT = "Cannot read and write to same file";
  113.             const char* MSG_ALREADY_EXISTS = "File already exists";
  114.         }
  115.  
  116.         const char IDB_STRING[bytes::header::IDB] = { 0x53, 0x52, 0x45, 0x53, 0x41, 0x52, 0x43, 0x48 };
  117.         const unsigned short VER_NUMBER = 4;
  118.     } // namespace impl
  119.  
  120.  
  121.     namespace impl {
  122.         static void func_error_if(bool condition, const char* msg, const char* file, int line)
  123.         {
  124.             if (condition) {
  125.                 std::string message = msg;
  126.                 message.append(std::string(" (") + file);
  127.                 message.append(std::string(" line: ") + std::to_string(line) + std::string(")"));
  128.                 throw SRAexcept(message.c_str());
  129.             }
  130.         }
  131.  
  132. #define error_if(condition, message) \
  133.         func_error_if(condition, message, __FILENAME__, __LINE__);
  134.  
  135.         // TODO: Endian checking
  136.         static short buffer_to_short(char* buffer, int offset = 0) {
  137.             short res = *(short*)buffer;
  138.             return res;
  139.         }
  140.        
  141.         static int buffer_to_int(char* buffer, int offset = 0) {
  142.             int res = *(int*)buffer;
  143.             return res;
  144.         }
  145.  
  146.         static bool compare_bytes(const char* data1, const char* data2, int count) {
  147.             return memcmp(data1, data2, count * sizeof(char)) == 0 ? true : false;
  148.         }
  149.  
  150.         static bool verify_idb(char* buffer) {
  151.             return compare_bytes(buffer, IDB_STRING, bytes::header::IDB);
  152.         }
  153.  
  154.         static bool file_exists(const std::string path) {
  155.             std::ifstream ifs(path);
  156.             return ifs.good();
  157.         }
  158.  
  159.         static unsigned int file_length(const std::string path) {
  160.             std::ifstream ifs(path, std::ifstream::binary | std::ifstream::ate);
  161.             error_if(!ifs.good(), except::MSG_CANT_OPEN);
  162.             return (unsigned int)ifs.tellg();
  163.         }
  164.  
  165.         static unsigned int file_length(std::ofstream& stream) {
  166.             unsigned int put = (unsigned int)stream.tellp();
  167.             stream.seekp(0, std::ofstream::end);
  168.             unsigned int size = (unsigned int)stream.tellp();
  169.             stream.seekp(0, put);
  170.             return size;
  171.         }
  172.  
  173.         int write_header_stub(std::ofstream& out)
  174.         {
  175.             out.seekp(0);
  176.  
  177.             using namespace bytes::header;
  178.  
  179.             int buffer_length = offsets::END_OF_HEADER + 31 & ~0x1F; // Add some padding to the buffer
  180.  
  181.             char* buffer = new char[buffer_length];
  182.             memset(buffer, 0, buffer_length * sizeof(*buffer));
  183.             memset(&buffer[offsets::END_OF_HEADER], 0x7F, buffer_length - offsets::END_OF_HEADER);
  184.  
  185.             out.write(buffer, buffer_length);
  186.             delete[] buffer;
  187.  
  188.             return buffer_length; // end of buffer
  189.         }
  190.  
  191.         void finalize_header(std::ofstream& out, int header_length, int num_blocks)
  192.         {
  193.             out.seekp(0);
  194.  
  195.             using namespace bytes::header;
  196.  
  197.             error_if(header_length < 32, except::MSG_NOT_WRITING);
  198.             char* buffer = new char[header_length];
  199.  
  200.             memcpy(buffer, IDB_STRING, IDB * sizeof(char)); // IDB
  201.             memset(&buffer[offsets::oCHKS], 'C', CHKS * sizeof(char)); // TODO: Checksum
  202.             memcpy(&buffer[offsets::oVER], &VER_NUMBER, VER * sizeof(char)); // Version
  203.             memcpy(&buffer[offsets::oOFFS], &header_length, OFFS * sizeof(char)); // Data offset
  204.  
  205.             unsigned int uts = (unsigned)time(nullptr);
  206.             memcpy(&buffer[offsets::oCD], &uts, CD * sizeof(char)); // Timestamp
  207.  
  208.             unsigned int size = file_length(out);
  209.             memcpy(&buffer[offsets::oLEN], &size, LEN * sizeof(char));
  210.             memcpy(&buffer[offsets::oARCO], &num_blocks, ARCO * sizeof(char));
  211.  
  212.             out.write(buffer, offsets::END_OF_HEADER);
  213.             delete[] buffer;
  214.         }
  215.  
  216.         int write_block_header(std::ofstream& out)
  217.         {
  218.             return 0;
  219.         }
  220.  
  221.         /*
  222.         * IO_Device
  223.         */
  224.         void IO_Device::read_bytes_at_offset(char* buffer, int offset, int count)
  225.         {
  226.             error_if(!in.is_open(), except::MSG_NOT_OPEN);
  227.             in.seekg(offset);
  228.             in.read(buffer, count);
  229.         }
  230.  
  231.         void IO_Device::erase_file_for_write()
  232.         {
  233.             close_streams();
  234.             out.open(file_path, std::ofstream::binary | std::ofstream::trunc);
  235.         }
  236.  
  237.         void IO_Device::close_streams()
  238.         {
  239.             if (in.is_open())
  240.                 in.close();
  241.             if (out.is_open())
  242.                 out.close();
  243.         }
  244.  
  245.         void IO_Device::open(std::string path)
  246.         {
  247.             using namespace bytes::header;
  248.             error_if(in.is_open(), except::MSG_ALREADY_OPEN);
  249.  
  250.             in.open(path, std::ifstream::binary);
  251.  
  252.             error_if(!in.is_open(), except::MSG_CANT_OPEN);
  253.  
  254.             file_path = path;
  255.  
  256.             char buffer[IDB];
  257.             in.read(buffer, IDB);
  258.             error_if(!verify_idb(buffer), std::string(std::string(except::MSG_NO_IDB_VERIF) + std::string(" (") + std::string(buffer) + std::string(")")).c_str());
  259.         }
  260.  
  261.         void IO_Device::close()
  262.         {
  263.             error_if(!in.is_open() && !out.is_open(), except::MSG_NOT_OPEN);
  264.             file_path = "";
  265.             close_streams();
  266.         }
  267.  
  268.         void IO_Device::create(std::string path, bool overwrite)
  269.         {
  270.             if (overwrite == false) {
  271.                 error_if(file_exists(path), except::MSG_ALREADY_EXISTS);
  272.             }
  273.  
  274.             if (file_exists(path)) {
  275.                 remove(path.c_str());
  276.             }
  277.  
  278.             close_streams();
  279.             out.open(path, std::ofstream::binary, std::ofstream::trunc);
  280.  
  281.             error_if(!out.is_open(), except::MSG_CANT_OPEN);
  282.             file_path = path;
  283.         }
  284.  
  285.         short IO_Device::get_version()
  286.         {
  287.             using namespace bytes::header;
  288.             char buffer[2];
  289.             read_bytes_at_offset(buffer, offsets::oVER, VER);
  290.             return buffer_to_short(buffer);
  291.         }
  292.  
  293.         int IO_Device::get_date()
  294.         {
  295.             using namespace bytes::header;
  296.             char buffer[4];
  297.             read_bytes_at_offset(buffer, offsets::oCD, CD);
  298.             return buffer_to_int(buffer);
  299.         }
  300.  
  301.         int IO_Device::get_size()
  302.         {
  303.             using namespace bytes::header;
  304.             char buffer[4];
  305.             read_bytes_at_offset(buffer, offsets::oLEN, LEN);
  306.             return buffer_to_int(buffer);
  307.         }
  308.  
  309.         short IO_Device::get_count()
  310.         {
  311.             using namespace bytes::header;
  312.             char buffer[2];
  313.             read_bytes_at_offset(buffer, offsets::oARCO, ARCO);
  314.             return buffer_to_short(buffer);
  315.         }
  316.  
  317.         void IO_Device::begin_writing()
  318.         {
  319.             error_if(writing, except::MSG_ALREADY_WRITING);
  320.  
  321.             using namespace bytes::header;
  322.  
  323.             writing = true;
  324.             erase_file_for_write();
  325.  
  326.             error_if(!out.is_open(), except::MSG_CANT_OPEN);
  327.             header_length = write_header_stub(out);
  328.         }
  329.  
  330.         void IO_Device::write_block(std::string resource)
  331.         {
  332.             error_if(!writing, except::MSG_NOT_WRITING);
  333.             error_if(!out.is_open(), except::MSG_NOT_OPEN);
  334.             error_if(resource.compare(file_path) != 0, except::MSG_IO_CONFLICT);
  335.  
  336.             in.close();
  337.             in.open(resource, std::ifstream::binary);
  338.  
  339.  
  340.         }
  341.  
  342.         void IO_Device::end_writing()
  343.         {
  344.             error_if(!out.is_open(), except::MSG_NOT_OPEN);
  345.             error_if(!writing, except::MSG_NOT_WRITING);
  346.  
  347.             using namespace bytes::header;
  348.  
  349.             finalize_header(out, header_length, blocks);
  350.  
  351.             writing = false;
  352.         }
  353.     } // namespace impl
  354. } // namespace sra
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement