134 const std::vector<uint8_t> &target,
135 std::vector<uint8_t> &patch) {
137 patch.insert(patch.end(), {
'B',
'P',
'S',
'1'});
139 encode(source.size(), patch);
140 encode(target.size(), patch);
143 size_t source_offset = 0;
144 size_t target_offset = 0;
145 int64_t source_rel_offset = 0;
146 int64_t target_rel_offset = 0;
148 while (target_offset < target.size()) {
149 if (source_offset < source.size() &&
150 source[source_offset] == target[target_offset]) {
152 while (source_offset + length < source.size() &&
153 target_offset + length < target.size() &&
154 source[source_offset + length] == target[target_offset + length]) {
157 encode((length - 1) << 2 | 0, patch);
158 source_offset += length;
159 target_offset += length;
163 target_offset + length < target.size() &&
164 (source_offset + length >= source.size() ||
165 source[source_offset + length] != target[target_offset + length])) {
169 encode((length - 1) << 2 | 1, patch);
170 for (
size_t i = 0; i < length; i++) {
171 patch.push_back(target[target_offset + i]);
173 target_offset += length;
178 if (source_offset < source.size()) {
180 int64_t offset = source_offset - source_rel_offset;
181 while (source_offset + length < source.size() &&
182 target_offset + length < target.size() &&
183 source[source_offset + length] == target[target_offset + length]) {
187 encode((length - 1) << 2 | 2, patch);
188 encode((offset < 0 ? 1 : 0) | (abs(offset) << 1), patch);
189 source_offset += length;
190 target_offset += length;
191 source_rel_offset = source_offset;
196 if (target_offset > 0) {
198 int64_t offset = target_offset - target_rel_offset;
199 while (target_offset + length < target.size() &&
200 target[target_offset - 1] == target[target_offset + length]) {
204 encode((length - 1) << 2 | 3, patch);
205 encode((offset < 0 ? 1 : 0) | (abs(offset) << 1), patch);
206 target_offset += length;
207 target_rel_offset = target_offset;
212 patch.resize(patch.size() + 12);
213 uint32_t source_checksum = crc32(source);
214 uint32_t target_checksum = crc32(target);
215 uint32_t patch_checksum = crc32(patch);
217 memcpy(patch.data() + patch.size() - 12, &source_checksum,
sizeof(uint32_t));
218 memcpy(patch.data() + patch.size() - 8, &target_checksum,
sizeof(uint32_t));
219 memcpy(patch.data() + patch.size() - 4, &patch_checksum,
sizeof(uint32_t));
223 const std::vector<uint8_t> &patch,
224 std::vector<uint8_t> &target) {
225 if (patch.size() < 4 || patch[0] !=
'B' || patch[1] !=
'P' ||
226 patch[2] !=
'S' || patch[3] !=
'1') {
227 throw std::runtime_error(
"Invalid patch format");
230 size_t patch_offset = 4;
231 uint64_t target_size = decode(patch, patch_offset);
232 uint64_t metadata_size = decode(patch, patch_offset);
233 patch_offset += metadata_size;
235 target.resize(target_size);
236 size_t source_offset = 0;
237 size_t target_offset = 0;
238 int64_t source_rel_offset = 0;
239 int64_t target_rel_offset = 0;
241 while (patch_offset < patch.size() - 12) {
242 uint64_t data = decode(patch, patch_offset);
243 uint64_t command = data & 3;
244 uint64_t length = (data >> 2) + 1;
249 target[target_offset++] = source[source_offset++];
254 target[target_offset++] = patch[patch_offset++];
259 int64_t offsetData = decode(patch, patch_offset);
260 source_rel_offset += (offsetData & 1 ? -1 : +1) * (offsetData >> 1);
262 target[target_offset++] = source[source_rel_offset++];
267 uint64_t offsetData = decode(patch, patch_offset);
268 target_rel_offset += (offsetData & 1 ? -1 : +1) * (offsetData >> 1);
270 target[target_offset++] = target[target_rel_offset++];
274 throw std::runtime_error(
"Invalid patch command");
278 uint32_t source_checksum;
279 uint32_t target_checksum;
280 uint32_t patch_checksum;
281 memcpy(&source_checksum, patch.data() + patch.size() - 12,
sizeof(uint32_t));
282 memcpy(&target_checksum, patch.data() + patch.size() - 8,
sizeof(uint32_t));
283 memcpy(&patch_checksum, patch.data() + patch.size() - 4,
sizeof(uint32_t));
285 if (source_checksum != crc32(source) || target_checksum != crc32(target) ||
287 crc32(std::vector<uint8_t>(patch.begin(), patch.end() - 4))) {
288 throw std::runtime_error(
"Checksum mismatch");