Archive.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include "Archive.h"
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <zlib.h>
  5. using WalrusRPG::PIAF::Archive;
  6. using WalrusRPG::PIAF::FileEntry;
  7. using WalrusRPG::PIAF::FileType;
  8. using WalrusRPG::PIAF::CompressionType;
  9. namespace
  10. {
  11. template <typename T> T read_big_endian_value(void *ptr)
  12. {
  13. T result = 0;
  14. uint8_t *data = (uint8_t *) ptr;
  15. for (unsigned i = 0; i < sizeof(T); i++)
  16. result |= data[i] << (8 * (sizeof(T) - 1 - i));
  17. return result;
  18. }
  19. // Must get a pointer on the file table.
  20. void load_file_table(FileEntry *entries, char *data, uint32_t nb_files)
  21. {
  22. for (unsigned index = 0; index < nb_files; index++)
  23. {
  24. char *current_entry_data = &data[index * 24];
  25. memcpy(entries[index].filename, current_entry_data, 8);
  26. entries[index].filename[8] = '\0'; // Makin' sure.
  27. entries[index].file_type =
  28. (FileType) read_big_endian_value<uint32_t>(&current_entry_data[8]);
  29. entries[index].compression_type =
  30. (CompressionType) read_big_endian_value<uint32_t>(
  31. &current_entry_data[12]);
  32. entries[index].file_size =
  33. read_big_endian_value<uint32_t>(&current_entry_data[16]);
  34. entries[index].data_offset =
  35. read_big_endian_value<uint32_t>(&current_entry_data[20]);
  36. }
  37. }
  38. }
  39. Archive::Archive(std::string &filepath) : Archive(filepath.c_str())
  40. {
  41. }
  42. Archive::Archive(const char *filepath) : file(nullptr), entries(nullptr)
  43. {
  44. if (filepath == nullptr)
  45. {
  46. // TODO : throw NPE
  47. //fprintf(stderr, "Null filepath\n");
  48. }
  49. file = fopen(filepath, "rb");
  50. if (file == nullptr)
  51. {
  52. // TODO : throw Couldn't open
  53. //fprintf(stderr, "Unable to open %s\n", filepath);
  54. }
  55. // loading stuff happens NOW
  56. // checking if the file is long enough to have a header
  57. fseek(file, 0L, SEEK_END);
  58. uint64_t filesize = ftell(file);
  59. fseek(file, 0L, SEEK_SET);
  60. if (filesize < 32)
  61. {
  62. // TODO : throw file too small
  63. //fprintf(stderr, "File too small\n");
  64. }
  65. char header_container[32] = {0};
  66. fread(header_container, sizeof(char), 32, file);
  67. if (strncmp(header_container, "WRPGPIAF", 8) != 0)
  68. {
  69. // TODO throw bad header
  70. //fprintf(stderr, "Bad header magic word\n");
  71. }
  72. uint32_t expected_checksum = read_big_endian_value<uint32_t>(&header_container[8]);
  73. uint32_t calculated_checksum = crc32(0L, (unsigned char *) &header_container[16], 16);
  74. if (expected_checksum != calculated_checksum)
  75. {
  76. // TODO throw bad checksum
  77. //fprintf(stderr, "Bad header checksum : %x != %x\n", expected_checksum, calculated_checksum);
  78. }
  79. // TODO : version checking
  80. version = read_big_endian_value<uint32_t>(&header_container[16]);
  81. /* if (version != CURRENT_PIAF_VERSION)
  82. * {
  83. * exception up;
  84. * throw up; // haha
  85. * }
  86. */
  87. nb_files = read_big_endian_value<uint32_t>(&header_container[20]);
  88. // printf("nb_files : %u\n", nb_files);
  89. data_size = read_big_endian_value<uint32_t>(&header_container[24]);
  90. uint64_t calculated_data_size = filesize - 32 - 24 * nb_files;
  91. if (data_size != calculated_data_size)
  92. {
  93. // T0D0 : throw wrong size exception
  94. // fprintf(stderr, "Bad data size : expected %u, got %lld\n", data_size, calculated_data_size);
  95. }
  96. if (nb_files != 0)
  97. {
  98. uint32_t expected_filetable_checksum =
  99. read_big_endian_value<uint32_t>(&header_container[12]);
  100. char *file_entry_data = new char[24 * nb_files];
  101. fseek(file, 32, SEEK_SET);
  102. fread(file_entry_data, sizeof(char), 24 * nb_files, file);
  103. if (expected_filetable_checksum !=
  104. crc32(0L, (unsigned char *) file_entry_data, 24 * nb_files))
  105. {
  106. // TODO : checksum exception
  107. // fprintf(stderr, "Bad filetable checksum\n");
  108. }
  109. entries = new FileEntry[nb_files];
  110. load_file_table(entries, file_entry_data, nb_files);
  111. delete[] file_entry_data;
  112. }
  113. }
  114. Archive::~Archive()
  115. {
  116. if(file != nullptr)
  117. fclose(file);
  118. if( entries != nullptr)
  119. delete[] entries;
  120. }
  121. FileEntry Archive::get_file_entry(char *filename)
  122. {
  123. for (uint32_t index = 0; index < nb_files; index++)
  124. {
  125. if (strcmp(entries[index].filename, filename) == 0)
  126. {
  127. return entries[index];
  128. }
  129. }
  130. // throw exception
  131. }
  132. /*PFile*/ void /*FileEntry*/ get(char *filename)
  133. {
  134. // return PFile(get_file_entry(filename));
  135. }