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 "third_party/courgette/ensemble.h" | |
8 | |
9 #include "base/basictypes.h" | |
10 #include "base/file_util.h" | |
11 #include "base/logging.h" | |
12 | |
13 #include "third_party/courgette/crc.h" | |
14 #include "third_party/courgette/image_info.h" | |
15 #include "third_party/courgette/region.h" | |
16 #include "third_party/courgette/streams.h" | |
17 #include "third_party/courgette/simple_delta.h" | |
18 #include "third_party/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 |