zip_parser.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /**
  2. * ZuluSCSI™ - Copyright (c) 2024 Rabbit Hole Computing™
  3. *
  4. * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
  5. *
  6. * https://www.gnu.org/licenses/gpl-3.0.html
  7. * ----
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version. 
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. * GNU General Public License for more details. 
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  20. **/
  21. #include "zip_parser.h"
  22. namespace zipparser
  23. {
  24. Parser::Parser()
  25. {
  26. filename_len = 0;
  27. Reset();
  28. }
  29. Parser::Parser(char const *filename, const size_t length)
  30. {
  31. Reset();
  32. SetMatchingFilename(filename, length);
  33. }
  34. void Parser::Reset()
  35. {
  36. target = parsing_target::signature;
  37. position = 0;
  38. deflate = false;
  39. filename_match = false;
  40. crc = 0;
  41. }
  42. void Parser::SetMatchingFilename(char const *filename, const size_t length)
  43. {
  44. if (filename[0] == '\0')
  45. filename_len = 0;
  46. else
  47. {
  48. this->filename = filename;
  49. filename_len = length;
  50. }
  51. }
  52. int32_t Parser::Parse(uint8_t const *buf, const size_t size)
  53. {
  54. if (filename_len == 0)
  55. return PARSE_ERROR;
  56. static bool matching = true;
  57. static bool central_dir = false;
  58. for (size_t idx = 0; idx < size; idx++)
  59. {
  60. switch (target)
  61. {
  62. case parsing_target::signature:
  63. if (++position == 1 && buf[idx] == 'P')
  64. break;
  65. if (position == 2 && buf[idx] == 'K')
  66. {
  67. central_dir = false;
  68. break;
  69. }
  70. if (position == 3 && buf[idx] == 0x03)
  71. break;
  72. if (position == 3 && buf[idx] == 0x01)
  73. {
  74. central_dir = true;
  75. break;
  76. }
  77. if (position == 4 && central_dir && buf[idx] == 0x2)
  78. {
  79. return PARSE_CENTRAL_DIR;
  80. }
  81. if (position == 4 && buf[idx] == 0x04)
  82. {
  83. position = 0;
  84. target = parsing_target::version;
  85. break;
  86. }
  87. return PARSE_ERROR;
  88. break;
  89. case parsing_target::version:
  90. if (++position == 2)
  91. {
  92. position = 0;
  93. target = parsing_target::flag;
  94. }
  95. break;
  96. case parsing_target::flag:
  97. if (++position == 2)
  98. {
  99. position = 0;
  100. target = parsing_target::method;
  101. }
  102. break;
  103. case parsing_target::method:
  104. if (++position == 1)
  105. {
  106. if (buf[idx] == 0x08 || buf[idx] == 0x00)
  107. deflate = buf[idx] == 0x08;
  108. else
  109. return PARSE_UNSUPPORTED_COMPRESSION;
  110. }
  111. if (position == 2)
  112. {
  113. if (buf[idx] == 0)
  114. {
  115. position = 0;
  116. target = parsing_target::modify_time;
  117. }
  118. else
  119. return PARSE_UNSUPPORTED_COMPRESSION;
  120. }
  121. break;
  122. case parsing_target::modify_time:
  123. if (++position == 2)
  124. {
  125. position = 0;
  126. target = parsing_target::modify_date;
  127. }
  128. break;
  129. case parsing_target::modify_date:
  130. if (++position == 2)
  131. {
  132. position = 0;
  133. target = parsing_target::crc;
  134. crc = 0;
  135. }
  136. break;
  137. case parsing_target::crc:
  138. crc |= buf[idx] << (8 * position++);
  139. if (position == 4)
  140. {
  141. target = parsing_target::size_compressed;
  142. compressed_data_size = 0;
  143. position = 0;
  144. }
  145. break;
  146. case parsing_target::size_compressed:
  147. compressed_data_size |= buf[idx] << (8 * position++);
  148. if (position == 4)
  149. {
  150. target = parsing_target::size_uncompressed;
  151. uncompressed_data_size = 0;
  152. position = 0;
  153. }
  154. break;
  155. case parsing_target::size_uncompressed:
  156. uncompressed_data_size |= buf[idx] << (8 * position++);
  157. if (position == 4)
  158. {
  159. target = parsing_target::filename_len;
  160. current_zip_filename_len = 0;
  161. position = 0;
  162. }
  163. break;
  164. case parsing_target::filename_len:
  165. current_zip_filename_len |= buf[idx] << (8 * position++);
  166. if (position == 2)
  167. {
  168. target = parsing_target::extra_field_len;
  169. extra_field_len = 0;
  170. position = 0;
  171. }
  172. break;
  173. case parsing_target::extra_field_len:
  174. extra_field_len |= buf[idx] << (8 * position++);
  175. if (position == 2)
  176. {
  177. target = parsing_target::filename;
  178. position = 0;
  179. filename_match = false;
  180. matching = true;
  181. }
  182. break;
  183. case parsing_target::filename:
  184. if (position <= current_zip_filename_len - 1)
  185. {
  186. if (matching && position < filename_len && filename[position] != buf[idx])
  187. matching = false;
  188. if (position == filename_len - 1 && matching)
  189. filename_match = true;
  190. if (position == current_zip_filename_len -1)
  191. {
  192. target = parsing_target::extra_field;
  193. matching = true;
  194. position = 0;
  195. if (extra_field_len == 0)
  196. {
  197. target = parsing_target::end;
  198. return idx + 1;
  199. }
  200. }
  201. else
  202. position++;
  203. }
  204. break;
  205. case parsing_target::extra_field:
  206. // extra_field_len should be at least 1 by this time
  207. if (++position == extra_field_len)
  208. {
  209. target = parsing_target::end;
  210. return idx + 1;
  211. }
  212. break;
  213. case parsing_target::end:
  214. return 0;
  215. break;
  216. }
  217. }
  218. return size;
  219. }
  220. bool Parser::FoundMatch()
  221. {
  222. return filename_match;
  223. }
  224. uint32_t Parser::GetCompressedSize()
  225. {
  226. return compressed_data_size;
  227. }
  228. }