76 const std::vector<uint8_t>& patch,
77 std::vector<uint8_t>& output) {
79 return absl::InvalidArgumentError(
"Source data is empty");
81 if (patch.size() < 16) {
82 return absl::InvalidArgumentError(
"Patch data is too small to be valid");
86 if (patch[0] !=
'B' || patch[1] !=
'P' || patch[2] !=
'S' ||
88 return absl::InvalidArgumentError(
89 "Invalid BPS patch header (expected BPS1)");
94 size_t patch_data_size = patch.size() - 4;
95 uint32_t stored_patch_crc = ReadLE32(&patch[patch_data_size]);
96 uint32_t computed_patch_crc =
CalculateCrc32(patch.data(), patch_data_size);
97 if (stored_patch_crc != computed_patch_crc) {
98 return absl::DataLossError(
"Patch CRC32 mismatch (corrupt patch file)");
103 uint64_t source_size = ReadVariableLength(patch.data(), patch.size(), offset);
104 uint64_t target_size = ReadVariableLength(patch.data(), patch.size(), offset);
105 uint64_t metadata_size =
106 ReadVariableLength(patch.data(), patch.size(), offset);
109 offset += metadata_size;
112 if (source.size() != source_size) {
113 return absl::InvalidArgumentError(
114 absl::StrFormat(
"Source size mismatch: expected %llu, got %zu",
115 source_size, source.size()));
119 uint32_t stored_source_crc = ReadLE32(&patch[patch_data_size - 8]);
121 if (stored_source_crc != computed_source_crc) {
122 return absl::DataLossError(
"Source ROM CRC32 mismatch");
126 output.resize(target_size);
127 size_t output_offset = 0;
128 int64_t source_relative_offset = 0;
129 int64_t target_relative_offset = 0;
133 size_t actions_end = patch.size() - 12;
135 while (offset < actions_end) {
136 uint64_t data = ReadVariableLength(patch.data(), patch.size(), offset);
137 uint64_t command = data & 3;
138 uint64_t length = (data >> 2) + 1;
143 for (uint64_t i = 0; i < length; ++i) {
144 if (output_offset >= target_size) {
145 return absl::InternalError(
"SourceRead: output overflow");
147 if (output_offset < source.size()) {
148 output[output_offset] = source[output_offset];
150 output[output_offset] = 0;
158 for (uint64_t i = 0; i < length; ++i) {
159 if (output_offset >= target_size || offset >= patch.size()) {
160 return absl::InternalError(
"TargetRead: overflow");
162 output[output_offset++] = patch[offset++];
168 uint64_t offset_data =
169 ReadVariableLength(patch.data(), patch.size(), offset);
170 int64_t relative = (offset_data & 1)
171 ? -(
static_cast<int64_t
>(offset_data >> 1) + 1)
172 :
static_cast<int64_t
>(offset_data >> 1);
173 source_relative_offset += relative;
174 for (uint64_t i = 0; i < length; ++i) {
175 if (output_offset >= target_size) {
176 return absl::InternalError(
"SourceCopy: output overflow");
178 if (source_relative_offset >= 0 &&
179 static_cast<size_t>(source_relative_offset) < source.size()) {
180 output[output_offset] = source[source_relative_offset];
182 output[output_offset] = 0;
185 source_relative_offset++;
191 uint64_t offset_data =
192 ReadVariableLength(patch.data(), patch.size(), offset);
193 int64_t relative = (offset_data & 1)
194 ? -(
static_cast<int64_t
>(offset_data >> 1) + 1)
195 :
static_cast<int64_t
>(offset_data >> 1);
196 target_relative_offset += relative;
197 for (uint64_t i = 0; i < length; ++i) {
198 if (output_offset >= target_size) {
199 return absl::InternalError(
"TargetCopy: output overflow");
201 if (target_relative_offset >= 0 &&
202 static_cast<size_t>(target_relative_offset) < output_offset) {
203 output[output_offset] = output[target_relative_offset];
205 output[output_offset] = 0;
208 target_relative_offset++;
213 return absl::InternalError(
214 absl::StrFormat(
"Unknown BPS command: %llu", command));
219 uint32_t stored_target_crc = ReadLE32(&patch[patch_data_size - 4]);
221 if (stored_target_crc != computed_target_crc) {
222 return absl::DataLossError(
"Target CRC32 mismatch after patch application");
225 return absl::OkStatus();
229 const std::vector<uint8_t>& target,
230 std::vector<uint8_t>& patch) {
231 if (source.empty()) {
232 return absl::InvalidArgumentError(
"Source data is empty");
234 if (target.empty()) {
235 return absl::InvalidArgumentError(
"Target data is empty");
241 patch.push_back(
'B');
242 patch.push_back(
'P');
243 patch.push_back(
'S');
244 patch.push_back(
'1');
247 WriteVariableLength(patch, source.size());
249 WriteVariableLength(patch, target.size());
251 WriteVariableLength(patch, 0);
265 size_t output_offset = 0;
267 while (output_offset < target.size()) {
269 size_t source_read_len = 0;
270 if (output_offset < source.size()) {
271 while (output_offset + source_read_len < target.size() &&
272 output_offset + source_read_len < source.size() &&
273 source[output_offset + source_read_len] ==
274 target[output_offset + source_read_len]) {
279 if (source_read_len >= 4 ||
280 (source_read_len > 0 &&
281 output_offset + source_read_len >= target.size())) {
283 uint64_t action = ((source_read_len - 1) << 2) | 0;
284 WriteVariableLength(patch, action);
285 output_offset += source_read_len;
288 size_t target_read_len = 1;
289 while (output_offset + target_read_len < target.size()) {
291 if (output_offset + target_read_len < source.size()) {
292 size_t match_len = 0;
293 while (output_offset + target_read_len + match_len < target.size() &&
294 output_offset + target_read_len + match_len < source.size() &&
295 source[output_offset + target_read_len + match_len] ==
296 target[output_offset + target_read_len + match_len]) {
299 if (match_len >= 4) {
307 uint64_t action = ((target_read_len - 1) << 2) | 1;
308 WriteVariableLength(patch, action);
311 for (
size_t i = 0; i < target_read_len; ++i) {
312 patch.push_back(target[output_offset + i]);
314 output_offset += target_read_len;
324 return absl::OkStatus();