BinGZipFile.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * Copyright (C) 2022 The V-Gears Team
  3. *
  4. * This file is part of V-Gears
  5. *
  6. * V-Gears is free software: you can redistribute it and/or modify it under
  7. * terms of the GNU General Public License as published by the Free Software
  8. * Foundation, version 3.0 (GPLv3) of the License.
  9. *
  10. * V-Gears is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <cassert>
  16. #include <zlib.h>
  17. #include "Logger.h"
  18. #include "BinGZipFile.h"
  19. BinGZipFile::BinGZipFile(const Ogre::String& file): File(file), file_count_(0){
  20. InnerGetNumberOfFiles();
  21. }
  22. BinGZipFile::BinGZipFile(File* file): File(file), file_count_(0){
  23. InnerGetNumberOfFiles();
  24. }
  25. BinGZipFile::BinGZipFile(File* file, u32 offset, u32 length):
  26. File(file, offset, length), file_count_(0)
  27. {InnerGetNumberOfFiles();}
  28. BinGZipFile::BinGZipFile(u8* buffer, u32 offset, u32 length):
  29. File(buffer, offset, length), file_count_(0)
  30. {
  31. InnerGetNumberOfFiles();
  32. }
  33. BinGZipFile::~BinGZipFile(){}
  34. File* BinGZipFile::ExtractGZip(u32 file_index){
  35. if (file_index >= file_count_) return NULL;
  36. u32 extract_size = 256 * 1024;
  37. u8* extract_buffer = (u8*)malloc(extract_size);
  38. int ret;
  39. z_stream strm;
  40. u32 offset = InnerGetFileOffset(file_index);
  41. strm.zalloc = Z_NULL; // Used to allocate the internal state.
  42. strm.zfree = Z_NULL; // Used to free the internal state.
  43. strm.opaque = Z_NULL; // Private data object passed to zalloc and zfree.
  44. strm.next_in = buffer_ + offset; //Next input byte.
  45. strm.avail_in = buffer_size_; // Number of bytes available at next_in.
  46. strm.next_out = extract_buffer; // Next output byte should be put there.
  47. strm.avail_out = extract_size; // Remaining free space at next_out.
  48. ret = inflateInit2(&strm, 15 + 32);
  49. if (ret != Z_OK){
  50. switch (ret){
  51. case Z_MEM_ERROR:
  52. inflateEnd(&strm);
  53. LOGGER->Log(
  54. "Warning: inflateInit2 - Z_MEM_ERROR in file " + file_name_
  55. );
  56. break;
  57. case Z_STREAM_ERROR:
  58. inflateEnd(&strm);
  59. LOGGER->Log(
  60. "Warning: inflateInit2 - Z_STREAM_ERROR in file " + file_name_
  61. );
  62. break;
  63. default:
  64. inflateEnd(&strm);
  65. LOGGER->Log(
  66. "Warning: inflateInit2 - unknown error in file " + file_name_
  67. );
  68. }
  69. return NULL;
  70. }
  71. do{
  72. if (strm.next_out == NULL){
  73. inflateEnd(&strm);
  74. LOGGER->Log("Warning: strm.next_out == NULL in file " + file_name_);
  75. return NULL;
  76. }
  77. ret = inflate(&strm, Z_NO_FLUSH);
  78. assert(ret != Z_STREAM_ERROR);
  79. switch (ret){
  80. case Z_NEED_DICT:
  81. inflateEnd(&strm);
  82. LOGGER->Log(
  83. "Warning: inflate - Z_NEED_DICT in file " + file_name_
  84. );
  85. return NULL;
  86. case Z_DATA_ERROR:
  87. inflateEnd(&strm);
  88. LOGGER->Log(
  89. "Warning: inflate - Z_DATA_ERROR in file " + file_name_
  90. );
  91. return NULL;
  92. case Z_MEM_ERROR:
  93. inflateEnd(&strm);
  94. LOGGER->Log(
  95. "Warning: inflate - Z_MEM_ERROR in file " + file_name_
  96. );
  97. return NULL;
  98. }
  99. if (ret != Z_STREAM_END){
  100. extract_buffer = (u8*) realloc(extract_buffer, extract_size * 2);
  101. if (extract_buffer == NULL){
  102. inflateEnd(&strm);
  103. LOGGER->Log(
  104. "Warning: extract_buffer == NULL in file " + file_name_
  105. );
  106. return NULL;
  107. }
  108. strm.next_out = (u8*)extract_buffer + extract_size;
  109. strm.avail_out = extract_size;
  110. extract_size *= 2;
  111. }
  112. } while (ret != Z_STREAM_END);
  113. extract_size = extract_size - strm.avail_out;
  114. (void)inflateEnd(&strm);
  115. if (ret != Z_STREAM_END){
  116. LOGGER->Log("Warning: ret != Z_STREAM_END in file " + file_name_);
  117. return NULL;
  118. }
  119. File* file = new File(extract_buffer, 0, extract_size);
  120. free(extract_buffer);
  121. return file;
  122. }
  123. u32 BinGZipFile::GetNumberOfFiles(){return file_count_;}
  124. void BinGZipFile::InnerGetNumberOfFiles(){
  125. file_count_ = 0;
  126. for (u32 pointer = 0; pointer < buffer_size_;){
  127. u16 temp = GetU16LE(pointer);
  128. pointer += 6;
  129. // Condition for GZip header.
  130. if (
  131. GetU32LE(pointer) == 0x00088B1F && GetU32LE(pointer + 4) == 0x00000000
  132. ){
  133. ++ file_count_;
  134. }
  135. pointer += temp;
  136. }
  137. if (file_count_ == 0){
  138. LOGGER->Log(
  139. "Warning: " + file_name_ + " isn't archive. number_of_files == 0"
  140. );
  141. }
  142. }
  143. u32 BinGZipFile::InnerGetFileOffset(u32 file_index){
  144. if (file_index >= file_count_) return 0;
  145. u32 current_file = 0;
  146. for (u32 pointer = 0; pointer < buffer_size_;){
  147. u16 temp = GetU16LE(pointer);
  148. pointer += 6;
  149. // Condition for GZip header
  150. if (
  151. GetU32LE(pointer) == 0x00088B1F && GetU32LE(pointer + 4) == 0x00000000
  152. ){
  153. if (file_index == current_file) return pointer;
  154. }
  155. ++ current_file;
  156. pointer += temp;
  157. }
  158. return 0;
  159. }