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/courgette_config.h"
14 #include "courgette/crc.h"
15 #include "courgette/patcher_x86_32.h"
16 #include "courgette/region.h"
17 #include "courgette/simple_delta.h"
18 #include "courgette/streams.h"
22 // EnsemblePatchApplication is all the logic and data required to apply the
24 class EnsemblePatchApplication
{
26 EnsemblePatchApplication();
27 ~EnsemblePatchApplication();
29 Status
ReadHeader(SourceStream
* header_stream
);
31 Status
InitBase(const Region
& region
);
33 Status
ValidateBase();
35 Status
ReadInitialParameters(SourceStream
* initial_parameters
);
37 Status
PredictTransformParameters(SinkStreamSet
* predicted_parameters
);
39 Status
SubpatchTransformParameters(SinkStreamSet
* prediction
,
40 SourceStream
* correction
,
41 SourceStreamSet
* corrected_parameters
);
43 Status
TransformUp(SourceStreamSet
* parameters
,
44 SinkStreamSet
* transformed_elements
);
46 Status
SubpatchTransformedElements(SinkStreamSet
* elements
,
47 SourceStream
* correction
,
48 SourceStreamSet
* corrected_elements
);
50 Status
TransformDown(SourceStreamSet
* transformed_elements
,
51 SinkStream
* basic_elements
);
53 Status
SubpatchFinalOutput(SourceStream
* original
,
54 SourceStream
* correction
,
55 SinkStream
* corrected_ensemble
);
58 Status
SubpatchStreamSets(SinkStreamSet
* predicted_items
,
59 SourceStream
* correction
,
60 SourceStreamSet
* corrected_items
,
61 SinkStream
* corrected_items_storage
);
63 Region base_region_
; // Location of in-memory copy of 'old' version.
65 uint32 source_checksum_
;
66 uint32 target_checksum_
;
67 uint32 final_patch_input_size_prediction_
;
69 std::vector
<TransformationPatcher
*> patchers_
;
71 SinkStream corrected_parameters_storage_
;
72 SinkStream corrected_elements_storage_
;
74 DISALLOW_COPY_AND_ASSIGN(EnsemblePatchApplication
);
77 EnsemblePatchApplication::EnsemblePatchApplication()
78 : source_checksum_(0), target_checksum_(0),
79 final_patch_input_size_prediction_(0) {
82 EnsemblePatchApplication::~EnsemblePatchApplication() {
83 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
88 Status
EnsemblePatchApplication::ReadHeader(SourceStream
* header_stream
) {
90 if (!header_stream
->ReadVarint32(&magic
))
91 return C_BAD_ENSEMBLE_MAGIC
;
93 if (magic
!= CourgettePatchFile::kMagic
)
94 return C_BAD_ENSEMBLE_MAGIC
;
97 if (!header_stream
->ReadVarint32(&version
))
98 return C_BAD_ENSEMBLE_VERSION
;
100 uint32 expected_ensemble_version
=
101 CourgetteConfig::GetInstance()->ensemble_version();
102 if (version
!= expected_ensemble_version
)
103 return C_BAD_ENSEMBLE_VERSION
;
105 if (!header_stream
->ReadVarint32(&source_checksum_
))
106 return C_BAD_ENSEMBLE_HEADER
;
108 if (!header_stream
->ReadVarint32(&target_checksum_
))
109 return C_BAD_ENSEMBLE_HEADER
;
111 if (!header_stream
->ReadVarint32(&final_patch_input_size_prediction_
))
112 return C_BAD_ENSEMBLE_HEADER
;
117 Status
EnsemblePatchApplication::InitBase(const Region
& region
) {
118 base_region_
.assign(region
);
122 Status
EnsemblePatchApplication::ValidateBase() {
123 uint32 checksum
= CalculateCrc(base_region_
.start(), base_region_
.length());
124 if (source_checksum_
!= checksum
)
125 return C_BAD_ENSEMBLE_CRC
;
130 Status
EnsemblePatchApplication::ReadInitialParameters(
131 SourceStream
* transformation_parameters
) {
132 uint32 number_of_transformations
= 0;
133 if (!transformation_parameters
->ReadVarint32(&number_of_transformations
))
134 return C_BAD_ENSEMBLE_HEADER
;
136 for (size_t i
= 0; i
< number_of_transformations
; ++i
) {
138 if (!transformation_parameters
->ReadVarint32(&kind
))
139 return C_BAD_ENSEMBLE_HEADER
;
141 TransformationPatcher
* patcher
= NULL
;
146 patcher
= new PatcherX86_32(base_region_
);
149 patcher
= new PatcherX86_32(base_region_
);
152 patcher
= new PatcherX86_32(base_region_
);
155 patcher
= new PatcherX86_32(base_region_
);
160 patchers_
.push_back(patcher
);
162 return C_BAD_ENSEMBLE_HEADER
;
165 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
166 Status status
= patchers_
[i
]->Init(transformation_parameters
);
171 // All transformation_parameters should have been consumed by the above loop.
172 if (!transformation_parameters
->Empty())
173 return C_BAD_ENSEMBLE_HEADER
;
178 Status
EnsemblePatchApplication::PredictTransformParameters(
179 SinkStreamSet
* all_predicted_parameters
) {
180 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
181 SinkStreamSet single_predicted_parameters
;
183 patchers_
[i
]->PredictTransformParameters(&single_predicted_parameters
);
186 if (!all_predicted_parameters
->WriteSet(&single_predicted_parameters
))
187 return C_STREAM_ERROR
;
192 Status
EnsemblePatchApplication::SubpatchTransformParameters(
193 SinkStreamSet
* predicted_parameters
,
194 SourceStream
* correction
,
195 SourceStreamSet
* corrected_parameters
) {
196 return SubpatchStreamSets(predicted_parameters
,
198 corrected_parameters
,
199 &corrected_parameters_storage_
);
202 Status
EnsemblePatchApplication::TransformUp(
203 SourceStreamSet
* parameters
,
204 SinkStreamSet
* transformed_elements
) {
205 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
206 SourceStreamSet single_parameters
;
207 if (!parameters
->ReadSet(&single_parameters
))
208 return C_STREAM_ERROR
;
209 SinkStreamSet single_transformed_element
;
210 Status status
= patchers_
[i
]->Transform(&single_parameters
,
211 &single_transformed_element
);
214 if (!single_parameters
.Empty())
215 return C_STREAM_NOT_CONSUMED
;
216 if (!transformed_elements
->WriteSet(&single_transformed_element
))
217 return C_STREAM_ERROR
;
220 if (!parameters
->Empty())
221 return C_STREAM_NOT_CONSUMED
;
225 Status
EnsemblePatchApplication::SubpatchTransformedElements(
226 SinkStreamSet
* predicted_elements
,
227 SourceStream
* correction
,
228 SourceStreamSet
* corrected_elements
) {
229 return SubpatchStreamSets(predicted_elements
,
232 &corrected_elements_storage_
);
235 Status
EnsemblePatchApplication::TransformDown(
236 SourceStreamSet
* transformed_elements
,
237 SinkStream
* basic_elements
) {
238 // Construct blob of original input followed by reformed elements.
240 if (!basic_elements
->Reserve(final_patch_input_size_prediction_
)) {
241 return C_STREAM_ERROR
;
244 // The original input:
245 if (!basic_elements
->Write(base_region_
.start(), base_region_
.length()))
246 return C_STREAM_ERROR
;
248 for (size_t i
= 0; i
< patchers_
.size(); ++i
) {
249 SourceStreamSet single_corrected_element
;
250 if (!transformed_elements
->ReadSet(&single_corrected_element
))
251 return C_STREAM_ERROR
;
252 Status status
= patchers_
[i
]->Reform(&single_corrected_element
,
256 if (!single_corrected_element
.Empty())
257 return C_STREAM_NOT_CONSUMED
;
260 if (!transformed_elements
->Empty())
261 return C_STREAM_NOT_CONSUMED
;
262 // We have totally consumed transformed_elements, so can free the
263 // storage to which it referred.
264 corrected_elements_storage_
.Retire();
269 Status
EnsemblePatchApplication::SubpatchFinalOutput(
270 SourceStream
* original
,
271 SourceStream
* correction
,
272 SinkStream
* corrected_ensemble
) {
273 Status delta_status
= ApplySimpleDelta(original
, correction
,
275 if (delta_status
!= C_OK
)
278 if (CalculateCrc(corrected_ensemble
->Buffer(),
279 corrected_ensemble
->Length()) != target_checksum_
)
280 return C_BAD_ENSEMBLE_CRC
;
285 Status
EnsemblePatchApplication::SubpatchStreamSets(
286 SinkStreamSet
* predicted_items
,
287 SourceStream
* correction
,
288 SourceStreamSet
* corrected_items
,
289 SinkStream
* corrected_items_storage
) {
290 SinkStream linearized_predicted_items
;
291 if (!predicted_items
->CopyTo(&linearized_predicted_items
))
292 return C_STREAM_ERROR
;
294 SourceStream prediction
;
295 prediction
.Init(linearized_predicted_items
);
297 Status status
= ApplySimpleDelta(&prediction
,
299 corrected_items_storage
);
303 if (!corrected_items
->Init(corrected_items_storage
->Buffer(),
304 corrected_items_storage
->Length()))
305 return C_STREAM_ERROR
;
310 Status
ApplyEnsemblePatch(SourceStream
* base
,
312 SinkStream
* output
) {
314 EnsemblePatchApplication patch_process
;
316 status
= patch_process
.ReadHeader(patch
);
320 status
= patch_process
.InitBase(Region(base
->Buffer(), base
->Remaining()));
324 status
= patch_process
.ValidateBase();
328 // The rest of the patch stream is a StreamSet.
329 SourceStreamSet patch_streams
;
330 patch_streams
.Init(patch
);
332 SourceStream
* transformation_descriptions
= patch_streams
.stream(0);
333 SourceStream
* parameter_correction
= patch_streams
.stream(1);
334 SourceStream
* transformed_elements_correction
= patch_streams
.stream(2);
335 SourceStream
* ensemble_correction
= patch_streams
.stream(3);
337 status
= patch_process
.ReadInitialParameters(transformation_descriptions
);
341 SinkStreamSet predicted_parameters
;
342 status
= patch_process
.PredictTransformParameters(&predicted_parameters
);
346 SourceStreamSet corrected_parameters
;
347 status
= patch_process
.SubpatchTransformParameters(&predicted_parameters
,
348 parameter_correction
,
349 &corrected_parameters
);
353 SinkStreamSet transformed_elements
;
354 status
= patch_process
.TransformUp(&corrected_parameters
,
355 &transformed_elements
);
359 SourceStreamSet corrected_transformed_elements
;
360 status
= patch_process
.SubpatchTransformedElements(
361 &transformed_elements
,
362 transformed_elements_correction
,
363 &corrected_transformed_elements
);
367 SinkStream original_ensemble_and_corrected_base_elements
;
368 status
= patch_process
.TransformDown(
369 &corrected_transformed_elements
,
370 &original_ensemble_and_corrected_base_elements
);
374 SourceStream final_patch_prediction
;
375 final_patch_prediction
.Init(original_ensemble_and_corrected_base_elements
);
376 status
= patch_process
.SubpatchFinalOutput(&final_patch_prediction
,
377 ensemble_correction
, output
);
384 Status
ApplyEnsemblePatch(const base::FilePath::CharType
* old_file_name
,
385 const base::FilePath::CharType
* patch_file_name
,
386 const base::FilePath::CharType
* new_file_name
) {
387 base::FilePath
patch_file_path(patch_file_name
);
388 base::MemoryMappedFile patch_file
;
389 if (!patch_file
.Initialize(patch_file_path
))
390 return C_READ_OPEN_ERROR
;
392 // 'Dry-run' the first step of the patch process to validate format of header.
393 SourceStream patch_header_stream
;
394 patch_header_stream
.Init(patch_file
.data(), patch_file
.length());
395 EnsemblePatchApplication patch_process
;
396 Status status
= patch_process
.ReadHeader(&patch_header_stream
);
400 // Read the old_file.
401 base::FilePath
old_file_path(old_file_name
);
402 base::MemoryMappedFile old_file
;
403 if (!old_file
.Initialize(old_file_path
))
406 // Apply patch on streams.
407 SourceStream old_source_stream
;
408 SourceStream patch_source_stream
;
409 old_source_stream
.Init(old_file
.data(), old_file
.length());
410 patch_source_stream
.Init(patch_file
.data(), patch_file
.length());
411 SinkStream new_sink_stream
;
412 status
= ApplyEnsemblePatch(&old_source_stream
, &patch_source_stream
,
417 // Write the patched data to |new_file_name|.
418 base::FilePath
new_file_path(new_file_name
);
422 reinterpret_cast<const char*>(new_sink_stream
.Buffer()),
423 static_cast<int>(new_sink_stream
.Length()));
425 return C_WRITE_OPEN_ERROR
;
426 if (static_cast<size_t>(written
) != new_sink_stream
.Length())
427 return C_WRITE_ERROR
;
432 } // namespace courgette