1 // Copyright (c) 2011 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.
5 // This file contains the code to apply a Courgette patch.
7 #include "courgette/ensemble.h"
9 #include "base/basictypes.h"
10 #include "base/file_util.h"
11 #include "base/files/memory_mapped_file.h"
12 #include "base/logging.h"
13 #include "courgette/crc.h"
14 #include "courgette/region.h"
15 #include "courgette/streams.h"
16 #include "courgette/simple_delta.h"
17 #include "courgette/patcher_x86_32.h"
21 // EnsemblePatchApplication is all the logic and data required to apply the
23 class EnsemblePatchApplication
{
25 EnsemblePatchApplication();
26 ~EnsemblePatchApplication();
28 Status
ReadHeader(SourceStream
* header_stream
);
30 Status
InitBase(const Region
& region
);
32 Status
ValidateBase();
34 Status
ReadInitialParameters(SourceStream
* initial_parameters
);
36 Status
PredictTransformParameters(SinkStreamSet
* predicted_parameters
);
38 Status
SubpatchTransformParameters(SinkStreamSet
* prediction
,
39 SourceStream
* correction
,
40 SourceStreamSet
* corrected_parameters
);
42 Status
TransformUp(SourceStreamSet
* parameters
,
43 SinkStreamSet
* transformed_elements
);
45 Status
SubpatchTransformedElements(SinkStreamSet
* elements
,
46 SourceStream
* correction
,
47 SourceStreamSet
* corrected_elements
);
49 Status
TransformDown(SourceStreamSet
* transformed_elements
,
50 SinkStream
* basic_elements
);
52 Status
SubpatchFinalOutput(SourceStream
* original
,
53 SourceStream
* correction
,
54 SinkStream
* corrected_ensemble
);
57 Status
SubpatchStreamSets(SinkStreamSet
* predicted_items
,
58 SourceStream
* correction
,
59 SourceStreamSet
* corrected_items
,
60 SinkStream
* corrected_items_storage
);
62 Region base_region_
; // Location of in-memory copy of 'old' version.
64 uint32 source_checksum_
;
65 uint32 target_checksum_
;
66 uint32 final_patch_input_size_prediction_
;
68 std::vector
<TransformationPatcher
*> patchers_
;
70 SinkStream corrected_parameters_storage_
;
71 SinkStream corrected_elements_storage_
;
73 DISALLOW_COPY_AND_ASSIGN(EnsemblePatchApplication
);
76 EnsemblePatchApplication::EnsemblePatchApplication()
77 : source_checksum_(0), target_checksum_(0),
78 final_patch_input_size_prediction_(0) {
81 EnsemblePatchApplication::~EnsemblePatchApplication() {
82 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
87 Status
EnsemblePatchApplication::ReadHeader(SourceStream
* header_stream
) {
89 if (!header_stream
->ReadVarint32(&magic
))
90 return C_BAD_ENSEMBLE_MAGIC
;
92 if (magic
!= CourgettePatchFile::kMagic
)
93 return C_BAD_ENSEMBLE_MAGIC
;
96 if (!header_stream
->ReadVarint32(&version
))
97 return C_BAD_ENSEMBLE_VERSION
;
99 if (version
!= CourgettePatchFile::kVersion
)
100 return C_BAD_ENSEMBLE_VERSION
;
102 if (!header_stream
->ReadVarint32(&source_checksum_
))
103 return C_BAD_ENSEMBLE_HEADER
;
105 if (!header_stream
->ReadVarint32(&target_checksum_
))
106 return C_BAD_ENSEMBLE_HEADER
;
108 if (!header_stream
->ReadVarint32(&final_patch_input_size_prediction_
))
109 return C_BAD_ENSEMBLE_HEADER
;
114 Status
EnsemblePatchApplication::InitBase(const Region
& region
) {
115 base_region_
.assign(region
);
119 Status
EnsemblePatchApplication::ValidateBase() {
120 uint32 checksum
= CalculateCrc(base_region_
.start(), base_region_
.length());
121 if (source_checksum_
!= checksum
)
122 return C_BAD_ENSEMBLE_CRC
;
127 Status
EnsemblePatchApplication::ReadInitialParameters(
128 SourceStream
* transformation_parameters
) {
129 uint32 number_of_transformations
= 0;
130 if (!transformation_parameters
->ReadVarint32(&number_of_transformations
))
131 return C_BAD_ENSEMBLE_HEADER
;
133 for (size_t i
= 0; i
< number_of_transformations
; ++i
) {
135 if (!transformation_parameters
->ReadVarint32(&kind
))
136 return C_BAD_ENSEMBLE_HEADER
;
138 TransformationPatcher
* patcher
= NULL
;
143 patcher
= new PatcherX86_32(base_region_
);
146 patcher
= new PatcherX86_32(base_region_
);
149 patcher
= new PatcherX86_32(base_region_
);
154 patchers_
.push_back(patcher
);
156 return C_BAD_ENSEMBLE_HEADER
;
159 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
160 Status status
= patchers_
[i
]->Init(transformation_parameters
);
165 // All transformation_parameters should have been consumed by the above loop.
166 if (!transformation_parameters
->Empty())
167 return C_BAD_ENSEMBLE_HEADER
;
172 Status
EnsemblePatchApplication::PredictTransformParameters(
173 SinkStreamSet
* all_predicted_parameters
) {
174 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
175 SinkStreamSet single_predicted_parameters
;
177 patchers_
[i
]->PredictTransformParameters(&single_predicted_parameters
);
180 if (!all_predicted_parameters
->WriteSet(&single_predicted_parameters
))
181 return C_STREAM_ERROR
;
186 Status
EnsemblePatchApplication::SubpatchTransformParameters(
187 SinkStreamSet
* predicted_parameters
,
188 SourceStream
* correction
,
189 SourceStreamSet
* corrected_parameters
) {
190 return SubpatchStreamSets(predicted_parameters
,
192 corrected_parameters
,
193 &corrected_parameters_storage_
);
196 Status
EnsemblePatchApplication::TransformUp(
197 SourceStreamSet
* parameters
,
198 SinkStreamSet
* transformed_elements
) {
199 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
200 SourceStreamSet single_parameters
;
201 if (!parameters
->ReadSet(&single_parameters
))
202 return C_STREAM_ERROR
;
203 SinkStreamSet single_transformed_element
;
204 Status status
= patchers_
[i
]->Transform(&single_parameters
,
205 &single_transformed_element
);
208 if (!single_parameters
.Empty())
209 return C_STREAM_NOT_CONSUMED
;
210 if (!transformed_elements
->WriteSet(&single_transformed_element
))
211 return C_STREAM_ERROR
;
214 if (!parameters
->Empty())
215 return C_STREAM_NOT_CONSUMED
;
219 Status
EnsemblePatchApplication::SubpatchTransformedElements(
220 SinkStreamSet
* predicted_elements
,
221 SourceStream
* correction
,
222 SourceStreamSet
* corrected_elements
) {
223 return SubpatchStreamSets(predicted_elements
,
226 &corrected_elements_storage_
);
229 Status
EnsemblePatchApplication::TransformDown(
230 SourceStreamSet
* transformed_elements
,
231 SinkStream
* basic_elements
) {
232 // Construct blob of original input followed by reformed elements.
234 if (!basic_elements
->Reserve(final_patch_input_size_prediction_
)) {
235 return C_STREAM_ERROR
;
238 // The original input:
239 if (!basic_elements
->Write(base_region_
.start(), base_region_
.length()))
240 return C_STREAM_ERROR
;
242 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
243 SourceStreamSet single_corrected_element
;
244 if (!transformed_elements
->ReadSet(&single_corrected_element
))
245 return C_STREAM_ERROR
;
246 Status status
= patchers_
[i
]->Reform(&single_corrected_element
,
250 if (!single_corrected_element
.Empty())
251 return C_STREAM_NOT_CONSUMED
;
254 if (!transformed_elements
->Empty())
255 return C_STREAM_NOT_CONSUMED
;
256 // We have totally consumed transformed_elements, so can free the
257 // storage to which it referred.
258 corrected_elements_storage_
.Retire();
263 Status
EnsemblePatchApplication::SubpatchFinalOutput(
264 SourceStream
* original
,
265 SourceStream
* correction
,
266 SinkStream
* corrected_ensemble
) {
267 Status delta_status
= ApplySimpleDelta(original
, correction
,
269 if (delta_status
!= C_OK
)
272 if (CalculateCrc(corrected_ensemble
->Buffer(),
273 corrected_ensemble
->Length()) != target_checksum_
)
274 return C_BAD_ENSEMBLE_CRC
;
279 Status
EnsemblePatchApplication::SubpatchStreamSets(
280 SinkStreamSet
* predicted_items
,
281 SourceStream
* correction
,
282 SourceStreamSet
* corrected_items
,
283 SinkStream
* corrected_items_storage
) {
284 SinkStream linearized_predicted_items
;
285 if (!predicted_items
->CopyTo(&linearized_predicted_items
))
286 return C_STREAM_ERROR
;
288 SourceStream prediction
;
289 prediction
.Init(linearized_predicted_items
);
291 Status status
= ApplySimpleDelta(&prediction
,
293 corrected_items_storage
);
297 if (!corrected_items
->Init(corrected_items_storage
->Buffer(),
298 corrected_items_storage
->Length()))
299 return C_STREAM_ERROR
;
304 Status
ApplyEnsemblePatch(SourceStream
* base
,
306 SinkStream
* output
) {
308 EnsemblePatchApplication patch_process
;
310 status
= patch_process
.ReadHeader(patch
);
314 status
= patch_process
.InitBase(Region(base
->Buffer(), base
->Remaining()));
318 status
= patch_process
.ValidateBase();
322 // The rest of the patch stream is a StreamSet.
323 SourceStreamSet patch_streams
;
324 patch_streams
.Init(patch
);
326 SourceStream
* transformation_descriptions
= patch_streams
.stream(0);
327 SourceStream
* parameter_correction
= patch_streams
.stream(1);
328 SourceStream
* transformed_elements_correction
= patch_streams
.stream(2);
329 SourceStream
* ensemble_correction
= patch_streams
.stream(3);
331 status
= patch_process
.ReadInitialParameters(transformation_descriptions
);
335 SinkStreamSet predicted_parameters
;
336 status
= patch_process
.PredictTransformParameters(&predicted_parameters
);
340 SourceStreamSet corrected_parameters
;
341 status
= patch_process
.SubpatchTransformParameters(&predicted_parameters
,
342 parameter_correction
,
343 &corrected_parameters
);
347 SinkStreamSet transformed_elements
;
348 status
= patch_process
.TransformUp(&corrected_parameters
,
349 &transformed_elements
);
353 SourceStreamSet corrected_transformed_elements
;
354 status
= patch_process
.SubpatchTransformedElements(
355 &transformed_elements
,
356 transformed_elements_correction
,
357 &corrected_transformed_elements
);
361 SinkStream original_ensemble_and_corrected_base_elements
;
362 status
= patch_process
.TransformDown(
363 &corrected_transformed_elements
,
364 &original_ensemble_and_corrected_base_elements
);
368 SourceStream final_patch_prediction
;
369 final_patch_prediction
.Init(original_ensemble_and_corrected_base_elements
);
370 status
= patch_process
.SubpatchFinalOutput(&final_patch_prediction
,
371 ensemble_correction
, output
);
378 Status
ApplyEnsemblePatch(const base::FilePath::CharType
* old_file_name
,
379 const base::FilePath::CharType
* patch_file_name
,
380 const base::FilePath::CharType
* new_file_name
) {
381 // First read enough of the patch file to validate the header is well-formed.
382 // A few varint32 numbers should fit in 100.
383 base::FilePath
patch_file_path(patch_file_name
);
384 base::MemoryMappedFile patch_file
;
385 if (!patch_file
.Initialize(patch_file_path
))
386 return C_READ_OPEN_ERROR
;
388 // 'Dry-run' the first step of the patch process to validate format of header.
389 SourceStream patch_header_stream
;
390 patch_header_stream
.Init(patch_file
.data(), patch_file
.length());
391 EnsemblePatchApplication patch_process
;
392 Status status
= patch_process
.ReadHeader(&patch_header_stream
);
396 // Read the old_file.
397 base::FilePath
old_file_path(old_file_name
);
398 base::MemoryMappedFile old_file
;
399 if (!old_file
.Initialize(old_file_path
))
402 // Apply patch on streams.
403 SourceStream old_source_stream
;
404 SourceStream patch_source_stream
;
405 old_source_stream
.Init(old_file
.data(), old_file
.length());
406 patch_source_stream
.Init(patch_file
.data(), patch_file
.length());
407 SinkStream new_sink_stream
;
408 status
= ApplyEnsemblePatch(&old_source_stream
, &patch_source_stream
,
413 // Write the patched data to |new_file_name|.
414 base::FilePath
new_file_path(new_file_name
);
416 file_util::WriteFile(
418 reinterpret_cast<const char*>(new_sink_stream
.Buffer()),
419 static_cast<int>(new_sink_stream
.Length()));
421 return C_WRITE_OPEN_ERROR
;
422 if (static_cast<size_t>(written
) != new_sink_stream
.Length())
423 return C_WRITE_ERROR
;