zip.hpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #pragma once
  2. #include <nall/file-map.hpp>
  3. #include <nall/string.hpp>
  4. #include <nall/vector.hpp>
  5. #include <nall/decode/inflate.hpp>
  6. namespace nall::Decode {
  7. struct ZIP {
  8. struct File {
  9. string name;
  10. const uint8_t* data;
  11. uint size;
  12. uint csize;
  13. uint cmode; //0 = uncompressed, 8 = deflate
  14. uint crc32;
  15. time_t timestamp;
  16. };
  17. ~ZIP() {
  18. close();
  19. }
  20. auto open(const string& filename) -> bool {
  21. close();
  22. if(fm.open(filename, file::mode::read) == false) return false;
  23. if(open(fm.data(), fm.size()) == false) {
  24. fm.close();
  25. return false;
  26. }
  27. return true;
  28. }
  29. auto open(const uint8_t* data, uint size) -> bool {
  30. if(size < 22) return false;
  31. filedata = data;
  32. filesize = size;
  33. file.reset();
  34. const uint8_t* footer = data + size - 22;
  35. while(true) {
  36. if(footer <= data + 22) return false;
  37. if(read(footer, 4) == 0x06054b50) {
  38. uint commentlength = read(footer + 20, 2);
  39. if(footer + 22 + commentlength == data + size) break;
  40. }
  41. footer--;
  42. }
  43. const uint8_t* directory = data + read(footer + 16, 4);
  44. while(true) {
  45. uint signature = read(directory + 0, 4);
  46. if(signature != 0x02014b50) break;
  47. File file;
  48. file.cmode = read(directory + 10, 2);
  49. file.crc32 = read(directory + 16, 4);
  50. file.csize = read(directory + 20, 4);
  51. file.size = read(directory + 24, 4);
  52. uint16_t dosTime = read(directory + 12, 2);
  53. uint16_t dosDate = read(directory + 14, 2);
  54. tm info = {};
  55. info.tm_sec = (dosTime >> 0 & 31) << 1;
  56. info.tm_min = (dosTime >> 5 & 63);
  57. info.tm_hour = (dosTime >> 11 & 31);
  58. info.tm_mday = (dosDate >> 0 & 31);
  59. info.tm_mon = (dosDate >> 5 & 15) - 1;
  60. info.tm_year = (dosDate >> 9 & 127) + 80;
  61. info.tm_isdst = -1;
  62. file.timestamp = mktime(&info);
  63. uint namelength = read(directory + 28, 2);
  64. uint extralength = read(directory + 30, 2);
  65. uint commentlength = read(directory + 32, 2);
  66. char* filename = new char[namelength + 1];
  67. memcpy(filename, directory + 46, namelength);
  68. filename[namelength] = 0;
  69. file.name = filename;
  70. delete[] filename;
  71. uint offset = read(directory + 42, 4);
  72. uint offsetNL = read(data + offset + 26, 2);
  73. uint offsetEL = read(data + offset + 28, 2);
  74. file.data = data + offset + 30 + offsetNL + offsetEL;
  75. directory += 46 + namelength + extralength + commentlength;
  76. this->file.append(file);
  77. }
  78. return true;
  79. }
  80. auto extract(File& file) -> vector<uint8_t> {
  81. vector<uint8_t> buffer;
  82. if(file.cmode == 0) {
  83. buffer.resize(file.size);
  84. memcpy(buffer.data(), file.data, file.size);
  85. }
  86. if(file.cmode == 8) {
  87. buffer.resize(file.size);
  88. if(inflate(buffer.data(), buffer.size(), file.data, file.csize) == false) {
  89. buffer.reset();
  90. }
  91. }
  92. return buffer;
  93. }
  94. auto close() -> void {
  95. if(fm) fm.close();
  96. }
  97. protected:
  98. file_map fm;
  99. const uint8_t* filedata;
  100. uint filesize;
  101. auto read(const uint8_t* data, uint size) -> uint {
  102. uint result = 0, shift = 0;
  103. while(size--) { result |= *data++ << shift; shift += 8; }
  104. return result;
  105. }
  106. public:
  107. vector<File> file;
  108. };
  109. }