patch.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * Copyright (c) 2023 Lain Bailey <[email protected]>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "updater.hpp"
  17. #include <stdint.h>
  18. #include <vector>
  19. using namespace std;
  20. /* ------------------------------------------------------------------------ */
  21. static int64_t offtin(const uint8_t *buf)
  22. {
  23. int64_t y;
  24. y = buf[7] & 0x7F;
  25. y = y * 256;
  26. y += buf[6];
  27. y = y * 256;
  28. y += buf[5];
  29. y = y * 256;
  30. y += buf[4];
  31. y = y * 256;
  32. y += buf[3];
  33. y = y * 256;
  34. y += buf[2];
  35. y = y * 256;
  36. y += buf[1];
  37. y = y * 256;
  38. y += buf[0];
  39. if (buf[7] & 0x80)
  40. y = -y;
  41. return y;
  42. }
  43. /* ------------------------------------------------------------------------ */
  44. int ApplyPatch(ZSTD_DCtx *zstdCtx, const wchar_t *patchFile,
  45. const wchar_t *targetFile)
  46. try {
  47. uint8_t header[24];
  48. int64_t newsize;
  49. bool success;
  50. WinHandle hPatch;
  51. WinHandle hTarget;
  52. /* --------------------------------- *
  53. * open patch and file to patch */
  54. hPatch = CreateFile(patchFile, GENERIC_READ, 0, nullptr, OPEN_EXISTING,
  55. 0, nullptr);
  56. if (!hPatch.Valid())
  57. throw int(GetLastError());
  58. hTarget = CreateFile(targetFile, GENERIC_READ, 0, nullptr,
  59. OPEN_EXISTING, 0, nullptr);
  60. if (!hTarget.Valid())
  61. throw int(GetLastError());
  62. /* --------------------------------- *
  63. * read patch header */
  64. DWORD read;
  65. DWORD patchFileSize;
  66. patchFileSize = GetFileSize(hPatch, nullptr);
  67. if (patchFileSize == INVALID_FILE_SIZE)
  68. throw int(GetLastError());
  69. success = !!ReadFile(hPatch, header, sizeof(header), &read, nullptr);
  70. if (success && read == sizeof(header)) {
  71. if (memcmp(header, "BOUF//ZSTD//DICT", 16))
  72. throw int(-4);
  73. } else {
  74. throw int(GetLastError());
  75. }
  76. /* --------------------------------- *
  77. * allocate new file size data */
  78. newsize = offtin(header + 16);
  79. if (newsize < 0 || newsize >= 0x7ffffffff)
  80. throw int(-5);
  81. vector<uint8_t> newData;
  82. try {
  83. newData.resize((size_t)newsize);
  84. } catch (...) {
  85. throw int(-1);
  86. }
  87. /* --------------------------------- *
  88. * read remainder of patch file */
  89. vector<uint8_t> patchData;
  90. try {
  91. patchData.resize(patchFileSize - sizeof(header));
  92. } catch (...) {
  93. throw int(-1);
  94. }
  95. if (!ReadFile(hPatch, &patchData[0], patchFileSize - sizeof(header),
  96. &read, nullptr))
  97. throw int(GetLastError());
  98. if (read != (patchFileSize - sizeof(header)))
  99. throw int(-1);
  100. /* --------------------------------- *
  101. * read old file */
  102. DWORD targetFileSize;
  103. targetFileSize = GetFileSize(hTarget, nullptr);
  104. if (targetFileSize == INVALID_FILE_SIZE)
  105. throw int(GetLastError());
  106. vector<uint8_t> oldData;
  107. try {
  108. oldData.resize(targetFileSize);
  109. } catch (...) {
  110. throw int(-1);
  111. }
  112. if (!ReadFile(hTarget, &oldData[0], targetFileSize, &read, nullptr))
  113. throw int(GetLastError());
  114. if (read != targetFileSize)
  115. throw int(-1);
  116. /* --------------------------------- *
  117. * patch to new file data */
  118. size_t result = ZSTD_decompress_usingDict(
  119. zstdCtx, &newData[0], newData.size(), patchData.data(),
  120. patchData.size(), oldData.data(), oldData.size());
  121. if (result != newsize || ZSTD_isError(result))
  122. throw int(-9);
  123. /* --------------------------------- *
  124. * write new file */
  125. hTarget = nullptr;
  126. hTarget = CreateFile(targetFile, GENERIC_WRITE, 0, nullptr,
  127. CREATE_ALWAYS, 0, nullptr);
  128. if (!hTarget.Valid())
  129. throw int(GetLastError());
  130. DWORD written;
  131. success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize, &written,
  132. nullptr);
  133. if (!success || written != newsize)
  134. throw int(GetLastError());
  135. return 0;
  136. } catch (int code) {
  137. return code;
  138. }
  139. int DecompressFile(ZSTD_DCtx *ctx, const wchar_t *tempFile, size_t newSize)
  140. try {
  141. WinHandle hTemp;
  142. hTemp = CreateFile(tempFile, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0,
  143. nullptr);
  144. if (!hTemp.Valid())
  145. throw int(GetLastError());
  146. /* --------------------------------- *
  147. * read compressed data */
  148. DWORD read;
  149. DWORD compressedFileSize;
  150. compressedFileSize = GetFileSize(hTemp, nullptr);
  151. if (compressedFileSize == INVALID_FILE_SIZE)
  152. throw int(GetLastError());
  153. vector<uint8_t> oldData;
  154. try {
  155. oldData.resize(compressedFileSize);
  156. } catch (...) {
  157. throw int(-1);
  158. }
  159. if (!ReadFile(hTemp, &oldData[0], compressedFileSize, &read, nullptr))
  160. throw int(GetLastError());
  161. if (read != compressedFileSize)
  162. throw int(-1);
  163. /* --------------------------------- *
  164. * decompress data */
  165. vector<uint8_t> newData;
  166. try {
  167. newData.resize((size_t)newSize);
  168. } catch (...) {
  169. throw int(-1);
  170. }
  171. size_t result = ZSTD_decompressDCtx(ctx, &newData[0], newData.size(),
  172. oldData.data(), oldData.size());
  173. if (result != newSize)
  174. throw int(-9);
  175. if (ZSTD_isError(result))
  176. throw int(-10);
  177. /* --------------------------------- *
  178. * overwrite temp file with new data */
  179. hTemp = nullptr;
  180. hTemp = CreateFile(tempFile, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
  181. 0, nullptr);
  182. if (!hTemp.Valid())
  183. throw int(GetLastError());
  184. bool success;
  185. DWORD written;
  186. success = !!WriteFile(hTemp, newData.data(), (DWORD)newSize, &written,
  187. nullptr);
  188. if (!success || written != newSize)
  189. throw int(GetLastError());
  190. return 0;
  191. } catch (int code) {
  192. return code;
  193. }