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_
);
151 patchers_
.push_back(patcher
);
153 return C_BAD_ENSEMBLE_HEADER
;
156 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
157 Status status
= patchers_
[i
]->Init(transformation_parameters
);
162 // All transformation_parameters should have been consumed by the above loop.
163 if (!transformation_parameters
->Empty())
164 return C_BAD_ENSEMBLE_HEADER
;
169 Status
EnsemblePatchApplication::PredictTransformParameters(
170 SinkStreamSet
* all_predicted_parameters
) {
171 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
172 SinkStreamSet single_predicted_parameters
;
174 patchers_
[i
]->PredictTransformParameters(&single_predicted_parameters
);
177 if (!all_predicted_parameters
->WriteSet(&single_predicted_parameters
))
178 return C_STREAM_ERROR
;
183 Status
EnsemblePatchApplication::SubpatchTransformParameters(
184 SinkStreamSet
* predicted_parameters
,
185 SourceStream
* correction
,
186 SourceStreamSet
* corrected_parameters
) {
187 return SubpatchStreamSets(predicted_parameters
,
189 corrected_parameters
,
190 &corrected_parameters_storage_
);
193 Status
EnsemblePatchApplication::TransformUp(
194 SourceStreamSet
* parameters
,
195 SinkStreamSet
* transformed_elements
) {
196 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
197 SourceStreamSet single_parameters
;
198 if (!parameters
->ReadSet(&single_parameters
))
199 return C_STREAM_ERROR
;
200 SinkStreamSet single_transformed_element
;
201 Status status
= patchers_
[i
]->Transform(&single_parameters
,
202 &single_transformed_element
);
205 if (!single_parameters
.Empty())
206 return C_STREAM_NOT_CONSUMED
;
207 if (!transformed_elements
->WriteSet(&single_transformed_element
))
208 return C_STREAM_ERROR
;
211 if (!parameters
->Empty())
212 return C_STREAM_NOT_CONSUMED
;
216 Status
EnsemblePatchApplication::SubpatchTransformedElements(
217 SinkStreamSet
* predicted_elements
,
218 SourceStream
* correction
,
219 SourceStreamSet
* corrected_elements
) {
220 return SubpatchStreamSets(predicted_elements
,
223 &corrected_elements_storage_
);
226 Status
EnsemblePatchApplication::TransformDown(
227 SourceStreamSet
* transformed_elements
,
228 SinkStream
* basic_elements
) {
229 // Construct blob of original input followed by reformed elements.
231 if (!basic_elements
->Reserve(final_patch_input_size_prediction_
)) {
232 return C_STREAM_ERROR
;
235 // The original input:
236 if (!basic_elements
->Write(base_region_
.start(), base_region_
.length()))
237 return C_STREAM_ERROR
;
239 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
240 SourceStreamSet single_corrected_element
;
241 if (!transformed_elements
->ReadSet(&single_corrected_element
))
242 return C_STREAM_ERROR
;
243 Status status
= patchers_
[i
]->Reform(&single_corrected_element
,
247 if (!single_corrected_element
.Empty())
248 return C_STREAM_NOT_CONSUMED
;
251 if (!transformed_elements
->Empty())
252 return C_STREAM_NOT_CONSUMED
;
253 // We have totally consumed transformed_elements, so can free the
254 // storage to which it referred.
255 corrected_elements_storage_
.Retire();
260 Status
EnsemblePatchApplication::SubpatchFinalOutput(
261 SourceStream
* original
,
262 SourceStream
* correction
,
263 SinkStream
* corrected_ensemble
) {
264 Status delta_status
= ApplySimpleDelta(original
, correction
,
266 if (delta_status
!= C_OK
)
269 if (CalculateCrc(corrected_ensemble
->Buffer(),
270 corrected_ensemble
->Length()) != target_checksum_
)
271 return C_BAD_ENSEMBLE_CRC
;
276 Status
EnsemblePatchApplication::SubpatchStreamSets(
277 SinkStreamSet
* predicted_items
,
278 SourceStream
* correction
,
279 SourceStreamSet
* corrected_items
,
280 SinkStream
* corrected_items_storage
) {
281 SinkStream linearized_predicted_items
;
282 if (!predicted_items
->CopyTo(&linearized_predicted_items
))
283 return C_STREAM_ERROR
;
285 SourceStream prediction
;
286 prediction
.Init(linearized_predicted_items
);
288 Status status
= ApplySimpleDelta(&prediction
,
290 corrected_items_storage
);
294 if (!corrected_items
->Init(corrected_items_storage
->Buffer(),
295 corrected_items_storage
->Length()))
296 return C_STREAM_ERROR
;
301 Status
ApplyEnsemblePatch(SourceStream
* base
,
303 SinkStream
* output
) {
305 EnsemblePatchApplication patch_process
;
307 status
= patch_process
.ReadHeader(patch
);
311 status
= patch_process
.InitBase(Region(base
->Buffer(), base
->Remaining()));
315 status
= patch_process
.ValidateBase();
319 // The rest of the patch stream is a StreamSet.
320 SourceStreamSet patch_streams
;
321 patch_streams
.Init(patch
);
323 SourceStream
* transformation_descriptions
= patch_streams
.stream(0);
324 SourceStream
* parameter_correction
= patch_streams
.stream(1);
325 SourceStream
* transformed_elements_correction
= patch_streams
.stream(2);
326 SourceStream
* ensemble_correction
= patch_streams
.stream(3);
328 status
= patch_process
.ReadInitialParameters(transformation_descriptions
);
332 SinkStreamSet predicted_parameters
;
333 status
= patch_process
.PredictTransformParameters(&predicted_parameters
);
337 SourceStreamSet corrected_parameters
;
338 status
= patch_process
.SubpatchTransformParameters(&predicted_parameters
,
339 parameter_correction
,
340 &corrected_parameters
);
344 SinkStreamSet transformed_elements
;
345 status
= patch_process
.TransformUp(&corrected_parameters
,
346 &transformed_elements
);
350 SourceStreamSet corrected_transformed_elements
;
351 status
= patch_process
.SubpatchTransformedElements(
352 &transformed_elements
,
353 transformed_elements_correction
,
354 &corrected_transformed_elements
);
358 SinkStream original_ensemble_and_corrected_base_elements
;
359 status
= patch_process
.TransformDown(
360 &corrected_transformed_elements
,
361 &original_ensemble_and_corrected_base_elements
);
365 SourceStream final_patch_prediction
;
366 final_patch_prediction
.Init(original_ensemble_and_corrected_base_elements
);
367 status
= patch_process
.SubpatchFinalOutput(&final_patch_prediction
,
368 ensemble_correction
, output
);
375 Status
ApplyEnsemblePatch(const base::FilePath::CharType
* old_file_name
,
376 const base::FilePath::CharType
* patch_file_name
,
377 const base::FilePath::CharType
* new_file_name
) {
378 // First read enough of the patch file to validate the header is well-formed.
379 // A few varint32 numbers should fit in 100.
380 base::FilePath
patch_file_path(patch_file_name
);
381 base::MemoryMappedFile patch_file
;
382 if (!patch_file
.Initialize(patch_file_path
))
383 return C_READ_OPEN_ERROR
;
385 // 'Dry-run' the first step of the patch process to validate format of header.
386 SourceStream patch_header_stream
;
387 patch_header_stream
.Init(patch_file
.data(), patch_file
.length());
388 EnsemblePatchApplication patch_process
;
389 Status status
= patch_process
.ReadHeader(&patch_header_stream
);
393 // Read the old_file.
394 base::FilePath
old_file_path(old_file_name
);
395 base::MemoryMappedFile old_file
;
396 if (!old_file
.Initialize(old_file_path
))
399 // Apply patch on streams.
400 SourceStream old_source_stream
;
401 SourceStream patch_source_stream
;
402 old_source_stream
.Init(old_file
.data(), old_file
.length());
403 patch_source_stream
.Init(patch_file
.data(), patch_file
.length());
404 SinkStream new_sink_stream
;
405 status
= ApplyEnsemblePatch(&old_source_stream
, &patch_source_stream
,
410 // Write the patched data to |new_file_name|.
411 base::FilePath
new_file_path(new_file_name
);
413 file_util::WriteFile(
415 reinterpret_cast<const char*>(new_sink_stream
.Buffer()),
416 static_cast<int>(new_sink_stream
.Length()));
418 return C_WRITE_OPEN_ERROR
;
419 if (static_cast<size_t>(written
) != new_sink_stream
.Length())
420 return C_WRITE_ERROR
;