OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 // This file contains the code to apply a Courgette patch. |
| 6 |
| 7 #include "courgette/ensemble.h" |
| 8 |
| 9 #include "base/basictypes.h" |
| 10 #include "base/file_util.h" |
| 11 #include "base/logging.h" |
| 12 |
| 13 #include "courgette/crc.h" |
| 14 #include "courgette/image_info.h" |
| 15 #include "courgette/region.h" |
| 16 #include "courgette/streams.h" |
| 17 #include "courgette/simple_delta.h" |
| 18 #include "courgette/win32_x86_patcher.h" |
| 19 |
| 20 namespace courgette { |
| 21 |
| 22 // EnsemblePatchApplication is all the logic and data required to apply the |
| 23 // multi-stage patch. |
| 24 class EnsemblePatchApplication { |
| 25 public: |
| 26 EnsemblePatchApplication(); |
| 27 ~EnsemblePatchApplication(); |
| 28 |
| 29 Status ReadHeader(SourceStream* header_stream); |
| 30 |
| 31 Status InitBase(const Region& region); |
| 32 |
| 33 Status ValidateBase(); |
| 34 |
| 35 Status ReadInitialParameters(SourceStream* initial_parameters); |
| 36 |
| 37 Status PredictTransformParameters(SinkStreamSet* predicted_parameters); |
| 38 |
| 39 Status SubpatchTransformParameters(SinkStreamSet* prediction, |
| 40 SourceStream* correction, |
| 41 SourceStreamSet* corrected_parameters); |
| 42 |
| 43 Status TransformUp(SourceStreamSet* parameters, |
| 44 SinkStreamSet* transformed_elements); |
| 45 |
| 46 Status SubpatchTransformedElements(SinkStreamSet* elements, |
| 47 SourceStream* correction, |
| 48 SourceStreamSet* corrected_elements); |
| 49 |
| 50 Status TransformDown(SourceStreamSet* transformed_elements, |
| 51 SinkStream* basic_elements); |
| 52 |
| 53 Status SubpatchFinalOutput(SourceStream* original, |
| 54 SourceStream* correction, |
| 55 SinkStream* corrected_ensemble); |
| 56 |
| 57 private: |
| 58 Status SubpatchStreamSets(SinkStreamSet* predicted_items, |
| 59 SourceStream* correction, |
| 60 SourceStreamSet* corrected_items, |
| 61 SinkStream* corrected_items_storage); |
| 62 |
| 63 Region base_region_; // Location of in-memory copy of 'old' version. |
| 64 |
| 65 uint32 source_checksum_; |
| 66 uint32 target_checksum_; |
| 67 |
| 68 std::vector<TransformationPatcher*> patchers_; |
| 69 |
| 70 SinkStream corrected_parameters_storage_; |
| 71 SinkStream corrected_elements_storage_; |
| 72 |
| 73 DISALLOW_COPY_AND_ASSIGN(EnsemblePatchApplication); |
| 74 }; |
| 75 |
| 76 EnsemblePatchApplication::EnsemblePatchApplication() |
| 77 : source_checksum_(0), target_checksum_(0) { |
| 78 } |
| 79 |
| 80 EnsemblePatchApplication::~EnsemblePatchApplication() { |
| 81 for (size_t i = 0; i < patchers_.size(); ++i) { |
| 82 delete patchers_[i]; |
| 83 } |
| 84 } |
| 85 |
| 86 Status EnsemblePatchApplication::ReadHeader(SourceStream* header_stream) { |
| 87 uint32 magic; |
| 88 if (!header_stream->ReadVarint32(&magic)) |
| 89 return C_BAD_ENSEMBLE_MAGIC; |
| 90 |
| 91 if (magic != CourgettePatchFile::kMagic) |
| 92 return C_BAD_ENSEMBLE_MAGIC; |
| 93 |
| 94 uint32 version; |
| 95 if (!header_stream->ReadVarint32(&version)) |
| 96 return C_BAD_ENSEMBLE_VERSION; |
| 97 |
| 98 if (version != CourgettePatchFile::kVersion) |
| 99 return C_BAD_ENSEMBLE_VERSION; |
| 100 |
| 101 if (!header_stream->ReadVarint32(&source_checksum_)) |
| 102 return C_BAD_ENSEMBLE_HEADER; |
| 103 |
| 104 if (!header_stream->ReadVarint32(&target_checksum_)) |
| 105 return C_BAD_ENSEMBLE_HEADER; |
| 106 |
| 107 return C_OK; |
| 108 } |
| 109 |
| 110 Status EnsemblePatchApplication::InitBase(const Region& region) { |
| 111 base_region_.assign(region); |
| 112 return C_OK; |
| 113 } |
| 114 |
| 115 Status EnsemblePatchApplication::ValidateBase() { |
| 116 uint32 checksum = CalculateCrc(base_region_.start(), base_region_.length()); |
| 117 if (source_checksum_ != checksum) |
| 118 return C_BAD_ENSEMBLE_CRC; |
| 119 |
| 120 return C_OK; |
| 121 } |
| 122 |
| 123 Status EnsemblePatchApplication::ReadInitialParameters( |
| 124 SourceStream* transformation_parameters) { |
| 125 uint32 number_of_transformations = 0; |
| 126 if (!transformation_parameters->ReadVarint32(&number_of_transformations)) |
| 127 return C_BAD_ENSEMBLE_HEADER; |
| 128 |
| 129 for (size_t i = 0; i < number_of_transformations; ++i) { |
| 130 uint32 kind; |
| 131 if (!transformation_parameters->ReadVarint32(&kind)) |
| 132 return C_BAD_ENSEMBLE_HEADER; |
| 133 |
| 134 if (kind == CourgettePatchFile::T_COURGETTE_WIN32_X86) { |
| 135 TransformationPatcher* patcher = |
| 136 new CourgetteWin32X86Patcher(base_region_); |
| 137 patchers_.push_back(patcher); |
| 138 } else { |
| 139 return C_BAD_ENSEMBLE_HEADER; |
| 140 } |
| 141 } |
| 142 |
| 143 for (size_t i = 0; i < patchers_.size(); ++i) { |
| 144 Status status = patchers_[i]->Init(transformation_parameters); |
| 145 if (status != C_OK) |
| 146 return status; |
| 147 } |
| 148 |
| 149 // All transformation_parameters should have been consumed by the above loop. |
| 150 if (!transformation_parameters->Empty()) |
| 151 return C_BAD_ENSEMBLE_HEADER; |
| 152 |
| 153 return C_OK; |
| 154 } |
| 155 |
| 156 Status EnsemblePatchApplication::PredictTransformParameters( |
| 157 SinkStreamSet* all_predicted_parameters) { |
| 158 for (size_t i = 0; i < patchers_.size(); ++i) { |
| 159 SinkStreamSet single_predicted_parameters; |
| 160 Status status = |
| 161 patchers_[i]->PredictTransformParameters(&single_predicted_parameters); |
| 162 if (status != C_OK) |
| 163 return status; |
| 164 if (!all_predicted_parameters->WriteSet(&single_predicted_parameters)) |
| 165 return C_STREAM_ERROR; |
| 166 } |
| 167 return C_OK; |
| 168 } |
| 169 |
| 170 Status EnsemblePatchApplication::SubpatchTransformParameters( |
| 171 SinkStreamSet* predicted_parameters, |
| 172 SourceStream* correction, |
| 173 SourceStreamSet* corrected_parameters) { |
| 174 return SubpatchStreamSets(predicted_parameters, |
| 175 correction, |
| 176 corrected_parameters, |
| 177 &corrected_parameters_storage_); |
| 178 } |
| 179 |
| 180 Status EnsemblePatchApplication::TransformUp( |
| 181 SourceStreamSet* parameters, |
| 182 SinkStreamSet* transformed_elements) { |
| 183 for (size_t i = 0; i < patchers_.size(); ++i) { |
| 184 SourceStreamSet single_parameters; |
| 185 if (!parameters->ReadSet(&single_parameters)) |
| 186 return C_STREAM_ERROR; |
| 187 SinkStreamSet single_transformed_element; |
| 188 Status status = patchers_[i]->Transform(&single_parameters, |
| 189 &single_transformed_element); |
| 190 if (status != C_OK) |
| 191 return status; |
| 192 if (!single_parameters.Empty()) |
| 193 return C_STREAM_NOT_CONSUMED; |
| 194 if (!transformed_elements->WriteSet(&single_transformed_element)) |
| 195 return C_STREAM_ERROR; |
| 196 } |
| 197 |
| 198 if (!parameters->Empty()) |
| 199 return C_STREAM_NOT_CONSUMED; |
| 200 return C_OK; |
| 201 } |
| 202 |
| 203 Status EnsemblePatchApplication::SubpatchTransformedElements( |
| 204 SinkStreamSet* predicted_elements, |
| 205 SourceStream* correction, |
| 206 SourceStreamSet* corrected_elements) { |
| 207 return SubpatchStreamSets(predicted_elements, |
| 208 correction, |
| 209 corrected_elements, |
| 210 &corrected_elements_storage_); |
| 211 } |
| 212 |
| 213 Status EnsemblePatchApplication::TransformDown( |
| 214 SourceStreamSet* transformed_elements, |
| 215 SinkStream* basic_elements) { |
| 216 // Construct blob of original input followed by reformed elements. |
| 217 |
| 218 // The original input: |
| 219 basic_elements->Write(base_region_.start(), base_region_.length()); |
| 220 |
| 221 for (size_t i = 0; i < patchers_.size(); ++i) { |
| 222 SourceStreamSet single_corrected_element; |
| 223 if (!transformed_elements->ReadSet(&single_corrected_element)) |
| 224 return C_STREAM_ERROR; |
| 225 Status status = patchers_[i]->Reform(&single_corrected_element, |
| 226 basic_elements); |
| 227 if (status != C_OK) |
| 228 return status; |
| 229 if (!single_corrected_element.Empty()) |
| 230 return C_STREAM_NOT_CONSUMED; |
| 231 } |
| 232 |
| 233 if (!transformed_elements->Empty()) |
| 234 return C_STREAM_NOT_CONSUMED; |
| 235 |
| 236 return C_OK; |
| 237 } |
| 238 |
| 239 Status EnsemblePatchApplication::SubpatchFinalOutput( |
| 240 SourceStream* original, |
| 241 SourceStream* correction, |
| 242 SinkStream* corrected_ensemble) { |
| 243 Status delta_status = ApplySimpleDelta(original, correction, |
| 244 corrected_ensemble); |
| 245 if (delta_status != C_OK) |
| 246 return delta_status; |
| 247 |
| 248 if (CalculateCrc(corrected_ensemble->Buffer(), |
| 249 corrected_ensemble->Length()) != target_checksum_) |
| 250 return C_BAD_ENSEMBLE_CRC; |
| 251 |
| 252 return C_OK; |
| 253 } |
| 254 |
| 255 Status EnsemblePatchApplication::SubpatchStreamSets( |
| 256 SinkStreamSet* predicted_items, |
| 257 SourceStream* correction, |
| 258 SourceStreamSet* corrected_items, |
| 259 SinkStream* corrected_items_storage) { |
| 260 SinkStream linearized_predicted_items; |
| 261 if (!predicted_items->CopyTo(&linearized_predicted_items)) |
| 262 return C_STREAM_ERROR; |
| 263 |
| 264 SourceStream prediction; |
| 265 prediction.Init(linearized_predicted_items); |
| 266 |
| 267 Status status = ApplySimpleDelta(&prediction, |
| 268 correction, |
| 269 corrected_items_storage); |
| 270 if (status != C_OK) |
| 271 return status; |
| 272 |
| 273 if (!corrected_items->Init(corrected_items_storage->Buffer(), |
| 274 corrected_items_storage->Length())) |
| 275 return C_STREAM_ERROR; |
| 276 |
| 277 return C_OK; |
| 278 } |
| 279 |
| 280 Status ApplyEnsemblePatch(SourceStream* base, |
| 281 SourceStream* patch, |
| 282 SinkStream* output) { |
| 283 Status status; |
| 284 EnsemblePatchApplication patch_process; |
| 285 |
| 286 status = patch_process.ReadHeader(patch); |
| 287 if (status != C_OK) |
| 288 return status; |
| 289 |
| 290 status = patch_process.InitBase(Region(base->Buffer(), base->Remaining())); |
| 291 if (status != C_OK) |
| 292 return status; |
| 293 |
| 294 status = patch_process.ValidateBase(); |
| 295 if (status != C_OK) |
| 296 return status; |
| 297 |
| 298 // The rest of the patch stream is a StreamSet. |
| 299 SourceStreamSet patch_streams; |
| 300 patch_streams.Init(patch); |
| 301 |
| 302 SourceStream* transformation_descriptions = patch_streams.stream(0); |
| 303 SourceStream* parameter_correction = patch_streams.stream(1); |
| 304 SourceStream* transformed_elements_correction = patch_streams.stream(2); |
| 305 SourceStream* ensemble_correction = patch_streams.stream(3); |
| 306 |
| 307 status = patch_process.ReadInitialParameters(transformation_descriptions); |
| 308 if (status != C_OK) |
| 309 return status; |
| 310 |
| 311 SinkStreamSet predicted_parameters; |
| 312 status = patch_process.PredictTransformParameters(&predicted_parameters); |
| 313 if (status != C_OK) |
| 314 return status; |
| 315 |
| 316 SourceStreamSet corrected_parameters; |
| 317 status = patch_process.SubpatchTransformParameters(&predicted_parameters, |
| 318 parameter_correction, |
| 319 &corrected_parameters); |
| 320 if (status != C_OK) |
| 321 return status; |
| 322 |
| 323 SinkStreamSet transformed_elements; |
| 324 status = patch_process.TransformUp(&corrected_parameters, |
| 325 &transformed_elements); |
| 326 if (status != C_OK) |
| 327 return status; |
| 328 |
| 329 SourceStreamSet corrected_transformed_elements; |
| 330 status = patch_process.SubpatchTransformedElements( |
| 331 &transformed_elements, |
| 332 transformed_elements_correction, |
| 333 &corrected_transformed_elements); |
| 334 if (status != C_OK) |
| 335 return status; |
| 336 |
| 337 SinkStream original_ensemble_and_corrected_base_elements; |
| 338 status = patch_process.TransformDown( |
| 339 &corrected_transformed_elements, |
| 340 &original_ensemble_and_corrected_base_elements); |
| 341 if (status != C_OK) |
| 342 return status; |
| 343 |
| 344 SourceStream final_patch_prediction; |
| 345 final_patch_prediction.Init(original_ensemble_and_corrected_base_elements); |
| 346 status = patch_process.SubpatchFinalOutput(&final_patch_prediction, |
| 347 ensemble_correction, output); |
| 348 if (status != C_OK) |
| 349 return status; |
| 350 |
| 351 return C_OK; |
| 352 } |
| 353 |
| 354 Status ApplyEnsemblePatch(const wchar_t* old_file_name, |
| 355 const wchar_t* patch_file_name, |
| 356 const wchar_t* new_file_name) { |
| 357 Status status; |
| 358 |
| 359 // First read enough of the patch file to validate the header is well-formed. |
| 360 // A few varint32 numbers should fit in 100. |
| 361 FilePath patch_file_path(patch_file_name); |
| 362 const int BIG_ENOUGH_FOR_HEADER = 100; |
| 363 char buffer[BIG_ENOUGH_FOR_HEADER]; |
| 364 int read_count = |
| 365 file_util::ReadFile(patch_file_path, buffer, sizeof(buffer)); |
| 366 if (read_count < 0) |
| 367 return C_READ_OPEN_ERROR; |
| 368 |
| 369 // 'Dry-run' the first step of the patch process to validate format of header. |
| 370 SourceStream patch_header_stream; |
| 371 patch_header_stream.Init(buffer, read_count); |
| 372 EnsemblePatchApplication patch_process; |
| 373 status = patch_process.ReadHeader(&patch_header_stream); |
| 374 if (status != C_OK) |
| 375 return status; |
| 376 |
| 377 // Header smells good so read the whole patch file for real. |
| 378 std::string patch_file_buffer; |
| 379 if (!file_util::ReadFileToString(patch_file_path, &patch_file_buffer)) |
| 380 return C_READ_ERROR; |
| 381 |
| 382 // Read the old_file. |
| 383 FilePath old_file_path(old_file_name); |
| 384 std::string old_file_buffer; |
| 385 if (!file_util::ReadFileToString(old_file_path, &old_file_buffer)) |
| 386 return C_READ_ERROR; |
| 387 |
| 388 // Apply patch on streams. |
| 389 SourceStream old_source_stream; |
| 390 SourceStream patch_source_stream; |
| 391 old_source_stream.Init(old_file_buffer); |
| 392 patch_source_stream.Init(patch_file_buffer); |
| 393 SinkStream new_sink_stream; |
| 394 status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream, |
| 395 &new_sink_stream); |
| 396 |
| 397 // Write the patched data to |new_file_name|. |
| 398 FilePath new_file_path(new_file_name); |
| 399 int written = |
| 400 file_util::WriteFile( |
| 401 new_file_path, |
| 402 reinterpret_cast<const char*>(new_sink_stream.Buffer()), |
| 403 new_sink_stream.Length()); |
| 404 if (written == -1) |
| 405 return C_WRITE_OPEN_ERROR; |
| 406 if (written != new_sink_stream.Length()) |
| 407 return C_WRITE_ERROR; |
| 408 |
| 409 return C_OK; |
| 410 } |
| 411 |
| 412 } // namespace |
OLD | NEW |