XPKMain.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /* Copyright (C) Teemu Suutari */
  2. #include <cstring>
  3. #include <memory>
  4. #include <algorithm>
  5. #include "common/SubBuffer.hpp"
  6. #include "common/OverflowCheck.hpp"
  7. #include "common/Common.hpp"
  8. #include "common/Common.hpp"
  9. #include "XPKMain.hpp"
  10. #include "XPKDecompressor.hpp"
  11. #include "ACCADecompressor.hpp"
  12. #include "ARTMDecompressor.hpp"
  13. #include "BLZWDecompressor.hpp"
  14. #include "BZIP2Decompressor.hpp"
  15. #include "CBR0Decompressor.hpp"
  16. #include "CRMDecompressor.hpp"
  17. #include "CYB2Decoder.hpp"
  18. #include "DEFLATEDecompressor.hpp"
  19. #include "DLTADecode.hpp"
  20. #include "FASTDecompressor.hpp"
  21. #include "FBR2Decompressor.hpp"
  22. #include "FRLEDecompressor.hpp"
  23. #include "HFMNDecompressor.hpp"
  24. #include "HUFFDecompressor.hpp"
  25. #include "ILZRDecompressor.hpp"
  26. #include "IMPDecompressor.hpp"
  27. #include "LHLBDecompressor.hpp"
  28. #include "LIN1Decompressor.hpp"
  29. #include "LIN2Decompressor.hpp"
  30. #include "LZBSDecompressor.hpp"
  31. #include "LZCBDecompressor.hpp"
  32. #include "LZW2Decompressor.hpp"
  33. #include "LZW4Decompressor.hpp"
  34. #include "LZW5Decompressor.hpp"
  35. #include "LZXDecompressor.hpp"
  36. #include "MASHDecompressor.hpp"
  37. #include "NONEDecompressor.hpp"
  38. #include "NUKEDecompressor.hpp"
  39. #include "PPDecompressor.hpp"
  40. #include "RAKEDecompressor.hpp"
  41. #include "RDCNDecompressor.hpp"
  42. #include "RLENDecompressor.hpp"
  43. #include "SDHCDecompressor.hpp"
  44. #include "SHR3Decompressor.hpp"
  45. #include "SHRIDecompressor.hpp"
  46. #include "SLZ3Decompressor.hpp"
  47. #include "SMPLDecompressor.hpp"
  48. #include "SQSHDecompressor.hpp"
  49. #include "SXSCDecompressor.hpp"
  50. #include "TDCSDecompressor.hpp"
  51. #include "ZENODecompressor.hpp"
  52. namespace ancient::internal
  53. {
  54. bool XPKMain::detectHeader(uint32_t hdr) noexcept
  55. {
  56. return hdr==FourCC("XPKF");
  57. }
  58. std::shared_ptr<Decompressor> XPKMain::create(const Buffer &packedData,bool verify,bool exactSizeKnown)
  59. {
  60. return std::make_shared<XPKMain>(packedData,verify,0);
  61. }
  62. static std::vector<std::pair<bool(*)(uint32_t),std::shared_ptr<XPKDecompressor>(*)(uint32_t,uint32_t,const Buffer&,std::shared_ptr<XPKDecompressor::State>&,bool)>> XPKDecompressors={
  63. {ACCADecompressor::detectHeaderXPK,ACCADecompressor::create},
  64. {ARTMDecompressor::detectHeaderXPK,ARTMDecompressor::create},
  65. {BLZWDecompressor::detectHeaderXPK,BLZWDecompressor::create},
  66. {BZIP2Decompressor::detectHeaderXPK,BZIP2Decompressor::create},
  67. {CBR0Decompressor::detectHeaderXPK,CBR0Decompressor::create},
  68. {CRMDecompressor::detectHeaderXPK,CRMDecompressor::create},
  69. {CYB2Decoder::detectHeaderXPK,CYB2Decoder::create},
  70. {DEFLATEDecompressor::detectHeaderXPK,DEFLATEDecompressor::create},
  71. {DLTADecode::detectHeaderXPK,DLTADecode::create},
  72. {FASTDecompressor::detectHeaderXPK,FASTDecompressor::create},
  73. {FBR2Decompressor::detectHeaderXPK,FBR2Decompressor::create},
  74. {FRLEDecompressor::detectHeaderXPK,FRLEDecompressor::create},
  75. {HFMNDecompressor::detectHeaderXPK,HFMNDecompressor::create},
  76. {HUFFDecompressor::detectHeaderXPK,HUFFDecompressor::create},
  77. {ILZRDecompressor::detectHeaderXPK,ILZRDecompressor::create},
  78. {IMPDecompressor::detectHeaderXPK,IMPDecompressor::create},
  79. {LHLBDecompressor::detectHeaderXPK,LHLBDecompressor::create},
  80. {LIN1Decompressor::detectHeaderXPK,LIN1Decompressor::create},
  81. {LIN2Decompressor::detectHeaderXPK,LIN2Decompressor::create},
  82. {LZBSDecompressor::detectHeaderXPK,LZBSDecompressor::create},
  83. {LZCBDecompressor::detectHeaderXPK,LZCBDecompressor::create},
  84. {LZW2Decompressor::detectHeaderXPK,LZW2Decompressor::create},
  85. {LZW4Decompressor::detectHeaderXPK,LZW4Decompressor::create},
  86. {LZW5Decompressor::detectHeaderXPK,LZW5Decompressor::create},
  87. {LZXDecompressor::detectHeaderXPK,LZXDecompressor::create},
  88. {MASHDecompressor::detectHeaderXPK,MASHDecompressor::create},
  89. {NONEDecompressor::detectHeaderXPK,NONEDecompressor::create},
  90. {NUKEDecompressor::detectHeaderXPK,NUKEDecompressor::create},
  91. {PPDecompressor::detectHeaderXPK,PPDecompressor::create},
  92. {RAKEDecompressor::detectHeaderXPK,RAKEDecompressor::create},
  93. {RDCNDecompressor::detectHeaderXPK,RDCNDecompressor::create},
  94. {RLENDecompressor::detectHeaderXPK,RLENDecompressor::create},
  95. {SDHCDecompressor::detectHeaderXPK,SDHCDecompressor::create},
  96. {SHR3Decompressor::detectHeaderXPK,SHR3Decompressor::create},
  97. {SHRIDecompressor::detectHeaderXPK,SHRIDecompressor::create},
  98. {SLZ3Decompressor::detectHeaderXPK,SLZ3Decompressor::create},
  99. {SMPLDecompressor::detectHeaderXPK,SMPLDecompressor::create},
  100. {SQSHDecompressor::detectHeaderXPK,SQSHDecompressor::create},
  101. {SXSCDecompressor::detectHeaderXPK,SXSCDecompressor::create},
  102. {TDCSDecompressor::detectHeaderXPK,TDCSDecompressor::create},
  103. {ZENODecompressor::detectHeaderXPK,ZENODecompressor::create}};
  104. XPKMain::XPKMain(const Buffer &packedData,bool verify,uint32_t recursionLevel) :
  105. _packedData(packedData)
  106. {
  107. if (packedData.size()<44) throw InvalidFormatError();
  108. uint32_t hdr=packedData.readBE32(0);
  109. if (!detectHeader(hdr)) throw InvalidFormatError();
  110. _packedSize=packedData.readBE32(4);
  111. _type=packedData.readBE32(8);
  112. _rawSize=packedData.readBE32(12);
  113. if (!_rawSize || !_packedSize) throw InvalidFormatError();
  114. if (_rawSize>getMaxRawSize() || _packedSize>getMaxPackedSize()) throw InvalidFormatError();
  115. uint8_t flags=packedData.read8(32);
  116. _longHeaders=(flags&1)?true:false;
  117. if (flags&2) throw InvalidFormatError(); // needs password. we do not support that
  118. if (flags&4) // extra header
  119. {
  120. _headerSize=38+uint32_t(packedData.readBE16(36));
  121. } else {
  122. _headerSize=36;
  123. }
  124. if (OverflowCheck::sum(_packedSize,8U)>packedData.size()) throw InvalidFormatError();
  125. bool found=false;
  126. for (auto &it : XPKDecompressors)
  127. {
  128. if (it.first(_type))
  129. {
  130. if (recursionLevel>=getMaxRecursionLevel()) throw InvalidFormatError();
  131. else {
  132. found=true;
  133. break;
  134. }
  135. }
  136. }
  137. if (!found) throw InvalidFormatError();
  138. auto headerChecksum=[](const Buffer &buffer,size_t offset,size_t len)->bool
  139. {
  140. if (!len || OverflowCheck::sum(offset,len)>buffer.size()) return false;
  141. const uint8_t *ptr=buffer.data()+offset;
  142. uint8_t tmp=0;
  143. for (size_t i=0;i<len;i++)
  144. tmp^=ptr[i];
  145. return !tmp;
  146. };
  147. // this implementation assumes align padding is zeros
  148. auto chunkChecksum=[](const Buffer &buffer,size_t offset,size_t len,uint16_t checkValue)->bool
  149. {
  150. if (!len || OverflowCheck::sum(offset,len)>buffer.size()) return false;
  151. const uint8_t *ptr=buffer.data()+offset;
  152. uint8_t tmp[2]={0,0};
  153. for (size_t i=0;i<len;i++)
  154. tmp[i&1]^=ptr[i];
  155. return tmp[0]==(checkValue>>8) && tmp[1]==(checkValue&0xff);
  156. };
  157. if (verify)
  158. {
  159. if (!headerChecksum(_packedData,0,36)) throw VerificationError();
  160. std::shared_ptr<XPKDecompressor::State> state;
  161. forEachChunk([&](const Buffer &header,const Buffer &chunk,uint32_t rawChunkSize,uint8_t chunkType)->bool
  162. {
  163. if (!headerChecksum(header,0,header.size())) throw VerificationError();
  164. uint16_t hdrCheck=header.readBE16(2);
  165. if (chunk.size() && !chunkChecksum(chunk,0,chunk.size(),hdrCheck)) throw VerificationError();
  166. if (chunkType==1)
  167. {
  168. auto sub=createDecompressor(_type,_recursionLevel,chunk,state,true);
  169. } else if (chunkType!=0 && chunkType!=15) throw InvalidFormatError();
  170. return true;
  171. });
  172. }
  173. }
  174. XPKMain::~XPKMain()
  175. {
  176. // nothing needed
  177. }
  178. const std::string &XPKMain::getName() const noexcept
  179. {
  180. std::shared_ptr<XPKDecompressor> sub;
  181. std::shared_ptr<XPKDecompressor::State> state;
  182. try
  183. {
  184. forEachChunk([&](const Buffer &header,const Buffer &chunk,uint32_t rawChunkSize,uint8_t chunkType)->bool
  185. {
  186. try
  187. {
  188. sub=createDecompressor(_type,_recursionLevel,chunk,state,false);
  189. } catch (const Error&) {
  190. // should not happen since the code is already tried out,
  191. // however, lets handle the case gracefully
  192. }
  193. return false;
  194. });
  195. } catch (const Buffer::Error&) {
  196. // ditto
  197. }
  198. static std::string invName="<invalid>";
  199. return (sub)?sub->getSubName():invName;
  200. }
  201. size_t XPKMain::getPackedSize() const noexcept
  202. {
  203. return _packedSize+8;
  204. }
  205. size_t XPKMain::getRawSize() const noexcept
  206. {
  207. return _rawSize;
  208. }
  209. void XPKMain::decompressImpl(Buffer &rawData,bool verify)
  210. {
  211. if (rawData.size()<_rawSize) throw DecompressionError();
  212. uint32_t destOffset=0;
  213. std::shared_ptr<XPKDecompressor::State> state;
  214. forEachChunk([&](const Buffer &header,const Buffer &chunk,uint32_t rawChunkSize,uint8_t chunkType)->bool
  215. {
  216. if (OverflowCheck::sum(destOffset,rawChunkSize)>rawData.size()) throw DecompressionError();
  217. if (!rawChunkSize) return true;
  218. ConstSubBuffer previousBuffer(rawData,0,destOffset);
  219. SubBuffer DestBuffer(rawData,destOffset,rawChunkSize);
  220. switch (chunkType)
  221. {
  222. case 0:
  223. if (rawChunkSize!=chunk.size()) throw DecompressionError();;
  224. std::memcpy(DestBuffer.data(),chunk.data(),rawChunkSize);
  225. break;
  226. case 1:
  227. {
  228. try
  229. {
  230. auto sub=createDecompressor(_type,_recursionLevel,chunk,state,false);
  231. sub->decompressImpl(DestBuffer,previousBuffer,verify);
  232. } catch (const InvalidFormatError&) {
  233. // we should throw a correct error
  234. throw DecompressionError();
  235. }
  236. }
  237. break;
  238. case 15:
  239. break;
  240. default:
  241. return false;
  242. }
  243. destOffset+=rawChunkSize;
  244. return true;
  245. });
  246. if (destOffset!=_rawSize) throw DecompressionError();
  247. if (verify)
  248. {
  249. if (std::memcmp(_packedData.data()+16,rawData.data(),std::min(_rawSize,16U))) throw DecompressionError();
  250. }
  251. }
  252. std::shared_ptr<XPKDecompressor> XPKMain::createDecompressor(uint32_t type,uint32_t recursionLevel,const Buffer &buffer,std::shared_ptr<XPKDecompressor::State> &state,bool verify)
  253. {
  254. // since this method is used externally, better check recursion level
  255. if (recursionLevel>=getMaxRecursionLevel()) throw InvalidFormatError();
  256. for (auto &it : XPKDecompressors)
  257. {
  258. if (it.first(type)) return it.second(type,recursionLevel,buffer,state,verify);
  259. }
  260. throw InvalidFormatError();
  261. }
  262. template <typename F>
  263. void XPKMain::forEachChunk(F func) const
  264. {
  265. uint32_t currentOffset=0,rawSize,packedSize;
  266. bool isLast=false;
  267. while (currentOffset<_packedSize+8 && !isLast)
  268. {
  269. auto readDualValue=[&](uint32_t offsetShort,uint32_t offsetLong,uint32_t &value)
  270. {
  271. if (_longHeaders)
  272. {
  273. value=_packedData.readBE32(currentOffset+offsetLong);
  274. } else {
  275. value=uint32_t(_packedData.readBE16(currentOffset+offsetShort));
  276. }
  277. };
  278. uint32_t chunkHeaderLen=_longHeaders?12:8;
  279. if (!currentOffset)
  280. {
  281. // return first;
  282. currentOffset=_headerSize;
  283. } else {
  284. uint32_t tmp;
  285. readDualValue(4,4,tmp);
  286. tmp=((tmp+3U)&~3U);
  287. if (OverflowCheck::sum(tmp,currentOffset,chunkHeaderLen)>_packedSize)
  288. throw InvalidFormatError();
  289. currentOffset+=chunkHeaderLen+tmp;
  290. }
  291. readDualValue(4,4,packedSize);
  292. readDualValue(6,8,rawSize);
  293. ConstSubBuffer hdr(_packedData,currentOffset,chunkHeaderLen);
  294. ConstSubBuffer chunk(_packedData,currentOffset+chunkHeaderLen,packedSize);
  295. uint8_t type=_packedData.read8(currentOffset);
  296. if (!func(hdr,chunk,rawSize,type)) return;
  297. if (type==15) isLast=true;
  298. }
  299. if (!isLast) throw InvalidFormatError();
  300. }
  301. }