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/files/file_util.h"
11 #include "base/files/memory_mapped_file.h"
12 #include "base/logging.h"
13 #include "courgette/crc.h"
14 #include "courgette/patcher_x86_32.h"
15 #include "courgette/region.h"
16 #include "courgette/simple_delta.h"
17 #include "courgette/streams.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_
);
152 patcher
= new PatcherX86_32(base_region_
);
157 patchers_
.push_back(patcher
);
159 return C_BAD_ENSEMBLE_HEADER
;
162 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
163 Status status
= patchers_
[i
]->Init(transformation_parameters
);
168 // All transformation_parameters should have been consumed by the above loop.
169 if (!transformation_parameters
->Empty())
170 return C_BAD_ENSEMBLE_HEADER
;
175 Status
EnsemblePatchApplication::PredictTransformParameters(
176 SinkStreamSet
* all_predicted_parameters
) {
177 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
178 SinkStreamSet single_predicted_parameters
;
180 patchers_
[i
]->PredictTransformParameters(&single_predicted_parameters
);
183 if (!all_predicted_parameters
->WriteSet(&single_predicted_parameters
))
184 return C_STREAM_ERROR
;
189 Status
EnsemblePatchApplication::SubpatchTransformParameters(
190 SinkStreamSet
* predicted_parameters
,
191 SourceStream
* correction
,
192 SourceStreamSet
* corrected_parameters
) {
193 return SubpatchStreamSets(predicted_parameters
,
195 corrected_parameters
,
196 &corrected_parameters_storage_
);
199 Status
EnsemblePatchApplication::TransformUp(
200 SourceStreamSet
* parameters
,
201 SinkStreamSet
* transformed_elements
) {
202 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
203 SourceStreamSet single_parameters
;
204 if (!parameters
->ReadSet(&single_parameters
))
205 return C_STREAM_ERROR
;
206 SinkStreamSet single_transformed_element
;
207 Status status
= patchers_
[i
]->Transform(&single_parameters
,
208 &single_transformed_element
);
211 if (!single_parameters
.Empty())
212 return C_STREAM_NOT_CONSUMED
;
213 if (!transformed_elements
->WriteSet(&single_transformed_element
))
214 return C_STREAM_ERROR
;
217 if (!parameters
->Empty())
218 return C_STREAM_NOT_CONSUMED
;
222 Status
EnsemblePatchApplication::SubpatchTransformedElements(
223 SinkStreamSet
* predicted_elements
,
224 SourceStream
* correction
,
225 SourceStreamSet
* corrected_elements
) {
226 return SubpatchStreamSets(predicted_elements
,
229 &corrected_elements_storage_
);
232 Status
EnsemblePatchApplication::TransformDown(
233 SourceStreamSet
* transformed_elements
,
234 SinkStream
* basic_elements
) {
235 // Construct blob of original input followed by reformed elements.
237 if (!basic_elements
->Reserve(final_patch_input_size_prediction_
)) {
238 return C_STREAM_ERROR
;
241 // The original input:
242 if (!basic_elements
->Write(base_region_
.start(), base_region_
.length()))
243 return C_STREAM_ERROR
;
245 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
246 SourceStreamSet single_corrected_element
;
247 if (!transformed_elements
->ReadSet(&single_corrected_element
))
248 return C_STREAM_ERROR
;
249 Status status
= patchers_
[i
]->Reform(&single_corrected_element
,
253 if (!single_corrected_element
.Empty())
254 return C_STREAM_NOT_CONSUMED
;
257 if (!transformed_elements
->Empty())
258 return C_STREAM_NOT_CONSUMED
;
259 // We have totally consumed transformed_elements, so can free the
260 // storage to which it referred.
261 corrected_elements_storage_
.Retire();
266 Status
EnsemblePatchApplication::SubpatchFinalOutput(
267 SourceStream
* original
,
268 SourceStream
* correction
,
269 SinkStream
* corrected_ensemble
) {
270 Status delta_status
= ApplySimpleDelta(original
, correction
,
272 if (delta_status
!= C_OK
)
275 if (CalculateCrc(corrected_ensemble
->Buffer(),
276 corrected_ensemble
->Length()) != target_checksum_
)
277 return C_BAD_ENSEMBLE_CRC
;
282 Status
EnsemblePatchApplication::SubpatchStreamSets(
283 SinkStreamSet
* predicted_items
,
284 SourceStream
* correction
,
285 SourceStreamSet
* corrected_items
,
286 SinkStream
* corrected_items_storage
) {
287 SinkStream linearized_predicted_items
;
288 if (!predicted_items
->CopyTo(&linearized_predicted_items
))
289 return C_STREAM_ERROR
;
291 SourceStream prediction
;
292 prediction
.Init(linearized_predicted_items
);
294 Status status
= ApplySimpleDelta(&prediction
,
296 corrected_items_storage
);
300 if (!corrected_items
->Init(corrected_items_storage
->Buffer(),
301 corrected_items_storage
->Length()))
302 return C_STREAM_ERROR
;
307 Status
ApplyEnsemblePatch(SourceStream
* base
,
309 SinkStream
* output
) {
311 EnsemblePatchApplication patch_process
;
313 status
= patch_process
.ReadHeader(patch
);
317 status
= patch_process
.InitBase(Region(base
->Buffer(), base
->Remaining()));
321 status
= patch_process
.ValidateBase();
325 // The rest of the patch stream is a StreamSet.
326 SourceStreamSet patch_streams
;
327 patch_streams
.Init(patch
);
329 SourceStream
* transformation_descriptions
= patch_streams
.stream(0);
330 SourceStream
* parameter_correction
= patch_streams
.stream(1);
331 SourceStream
* transformed_elements_correction
= patch_streams
.stream(2);
332 SourceStream
* ensemble_correction
= patch_streams
.stream(3);
334 status
= patch_process
.ReadInitialParameters(transformation_descriptions
);
338 SinkStreamSet predicted_parameters
;
339 status
= patch_process
.PredictTransformParameters(&predicted_parameters
);
343 SourceStreamSet corrected_parameters
;
344 status
= patch_process
.SubpatchTransformParameters(&predicted_parameters
,
345 parameter_correction
,
346 &corrected_parameters
);
350 SinkStreamSet transformed_elements
;
351 status
= patch_process
.TransformUp(&corrected_parameters
,
352 &transformed_elements
);
356 SourceStreamSet corrected_transformed_elements
;
357 status
= patch_process
.SubpatchTransformedElements(
358 &transformed_elements
,
359 transformed_elements_correction
,
360 &corrected_transformed_elements
);
364 SinkStream original_ensemble_and_corrected_base_elements
;
365 status
= patch_process
.TransformDown(
366 &corrected_transformed_elements
,
367 &original_ensemble_and_corrected_base_elements
);
371 SourceStream final_patch_prediction
;
372 final_patch_prediction
.Init(original_ensemble_and_corrected_base_elements
);
373 status
= patch_process
.SubpatchFinalOutput(&final_patch_prediction
,
374 ensemble_correction
, output
);
381 Status
ApplyEnsemblePatch(const base::FilePath::CharType
* old_file_name
,
382 const base::FilePath::CharType
* patch_file_name
,
383 const base::FilePath::CharType
* new_file_name
) {
384 base::FilePath
patch_file_path(patch_file_name
);
385 base::MemoryMappedFile patch_file
;
386 if (!patch_file
.Initialize(patch_file_path
))
387 return C_READ_OPEN_ERROR
;
389 // 'Dry-run' the first step of the patch process to validate format of header.
390 SourceStream patch_header_stream
;
391 patch_header_stream
.Init(patch_file
.data(), patch_file
.length());
392 EnsemblePatchApplication patch_process
;
393 Status status
= patch_process
.ReadHeader(&patch_header_stream
);
397 // Read the old_file.
398 base::FilePath
old_file_path(old_file_name
);
399 base::MemoryMappedFile old_file
;
400 if (!old_file
.Initialize(old_file_path
))
403 // Apply patch on streams.
404 SourceStream old_source_stream
;
405 SourceStream patch_source_stream
;
406 old_source_stream
.Init(old_file
.data(), old_file
.length());
407 patch_source_stream
.Init(patch_file
.data(), patch_file
.length());
408 SinkStream new_sink_stream
;
409 status
= ApplyEnsemblePatch(&old_source_stream
, &patch_source_stream
,
414 // Write the patched data to |new_file_name|.
415 base::FilePath
new_file_path(new_file_name
);
419 reinterpret_cast<const char*>(new_sink_stream
.Buffer()),
420 static_cast<int>(new_sink_stream
.Length()));
422 return C_WRITE_OPEN_ERROR
;
423 if (static_cast<size_t>(written
) != new_sink_stream
.Length())
424 return C_WRITE_ERROR
;