[M108 Migration][HBBTV] Implement ewk_context_register_jsplugin_mime_types API
[platform/framework/web/chromium-efl.git] / courgette / ensemble_apply.cc
1 // Copyright 2011 The Chromium Authors
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 "courgette/ensemble.h"
8
9 #include <stddef.h>
10 #include <stdint.h>
11
12 #include <memory>
13 #include <utility>
14
15 #include "base/check.h"
16 #include "base/files/file.h"
17 #include "base/files/file_util.h"
18 #include "base/files/memory_mapped_file.h"
19 #include "courgette/crc.h"
20 #include "courgette/patcher_x86_32.h"
21 #include "courgette/region.h"
22 #include "courgette/simple_delta.h"
23 #include "courgette/streams.h"
24
25 namespace courgette {
26
27 // EnsemblePatchApplication is all the logic and data required to apply the
28 // multi-stage patch.
29 class EnsemblePatchApplication {
30  public:
31   EnsemblePatchApplication();
32
33   EnsemblePatchApplication(const EnsemblePatchApplication&) = delete;
34   EnsemblePatchApplication& operator=(const EnsemblePatchApplication&) = delete;
35
36   ~EnsemblePatchApplication() = default;
37
38   Status ReadHeader(SourceStream* header_stream);
39
40   Status InitBase(const Region& region);
41
42   Status ValidateBase();
43
44   Status ReadInitialParameters(SourceStream* initial_parameters);
45
46   Status PredictTransformParameters(SinkStreamSet* predicted_parameters);
47
48   Status SubpatchTransformParameters(SinkStreamSet* prediction,
49                                      SourceStream* correction,
50                                      SourceStreamSet* corrected_parameters);
51
52   Status TransformUp(SourceStreamSet* parameters,
53                      SinkStreamSet* transformed_elements);
54
55   Status SubpatchTransformedElements(SinkStreamSet* elements,
56                                      SourceStream* correction,
57                                      SourceStreamSet* corrected_elements);
58
59   Status TransformDown(SourceStreamSet* transformed_elements,
60                        SinkStream* basic_elements);
61
62   Status SubpatchFinalOutput(SourceStream* original,
63                              SourceStream* correction,
64                              SinkStream* corrected_ensemble);
65
66  private:
67   Status SubpatchStreamSets(SinkStreamSet* predicted_items,
68                             SourceStream* correction,
69                             SourceStreamSet* corrected_items,
70                             SinkStream* corrected_items_storage);
71
72   Region base_region_;       // Location of in-memory copy of 'old' version.
73
74   uint32_t source_checksum_;
75   uint32_t target_checksum_;
76   uint32_t final_patch_input_size_prediction_;
77
78   std::vector<std::unique_ptr<TransformationPatcher>> patchers_;
79
80   SinkStream corrected_parameters_storage_;
81   SinkStream corrected_elements_storage_;
82 };
83
84 EnsemblePatchApplication::EnsemblePatchApplication()
85     : source_checksum_(0), target_checksum_(0),
86       final_patch_input_size_prediction_(0) {
87 }
88
89 Status EnsemblePatchApplication::ReadHeader(SourceStream* header_stream) {
90   uint32_t magic;
91   if (!header_stream->ReadVarint32(&magic))
92     return C_BAD_ENSEMBLE_MAGIC;
93
94   if (magic != CourgettePatchFile::kMagic)
95     return C_BAD_ENSEMBLE_MAGIC;
96
97   uint32_t version;
98   if (!header_stream->ReadVarint32(&version))
99     return C_BAD_ENSEMBLE_VERSION;
100
101   if (version != CourgettePatchFile::kVersion)
102     return C_BAD_ENSEMBLE_VERSION;
103
104   if (!header_stream->ReadVarint32(&source_checksum_))
105     return C_BAD_ENSEMBLE_HEADER;
106
107   if (!header_stream->ReadVarint32(&target_checksum_))
108     return C_BAD_ENSEMBLE_HEADER;
109
110   if (!header_stream->ReadVarint32(&final_patch_input_size_prediction_))
111     return C_BAD_ENSEMBLE_HEADER;
112
113   return C_OK;
114 }
115
116 Status EnsemblePatchApplication::InitBase(const Region& region) {
117   base_region_.assign(region);
118   return C_OK;
119 }
120
121 Status EnsemblePatchApplication::ValidateBase() {
122   uint32_t checksum = CalculateCrc(base_region_.start(), base_region_.length());
123   if (source_checksum_ != checksum)
124     return C_BAD_ENSEMBLE_CRC;
125
126   return C_OK;
127 }
128
129 Status EnsemblePatchApplication::ReadInitialParameters(
130     SourceStream* transformation_parameters) {
131   uint32_t number_of_transformations = 0;
132   if (!transformation_parameters->ReadVarint32(&number_of_transformations))
133     return C_BAD_ENSEMBLE_HEADER;
134
135   for (size_t i = 0;  i < number_of_transformations;  ++i) {
136     uint32_t kind;
137     if (!transformation_parameters->ReadVarint32(&kind))
138       return C_BAD_ENSEMBLE_HEADER;
139
140     std::unique_ptr<TransformationPatcher> patcher;
141
142     switch (kind) {
143       case EXE_WIN_32_X86:  // Fall through.
144       case EXE_ELF_32_X86:
145       case EXE_WIN_32_X64:
146         patcher = std::make_unique<PatcherX86_32>(base_region_);
147         break;
148       default:
149         return C_BAD_ENSEMBLE_HEADER;
150     }
151
152     DCHECK(patcher);
153     patchers_.push_back(std::move(patcher));
154   }
155
156   for (size_t i = 0;  i < patchers_.size();  ++i) {
157     Status status = patchers_[i]->Init(transformation_parameters);
158     if (status != C_OK)
159       return status;
160   }
161
162   // All transformation_parameters should have been consumed by the above loop.
163   if (!transformation_parameters->Empty())
164     return C_BAD_ENSEMBLE_HEADER;
165
166   return C_OK;
167 }
168
169 Status EnsemblePatchApplication::PredictTransformParameters(
170     SinkStreamSet* all_predicted_parameters) {
171   for (size_t i = 0;  i < patchers_.size();  ++i) {
172     SinkStreamSet single_predicted_parameters;
173     Status status =
174         patchers_[i]->PredictTransformParameters(&single_predicted_parameters);
175     if (status != C_OK)
176       return status;
177     if (!all_predicted_parameters->WriteSet(&single_predicted_parameters))
178       return C_STREAM_ERROR;
179   }
180   return C_OK;
181 }
182
183 Status EnsemblePatchApplication::SubpatchTransformParameters(
184     SinkStreamSet* predicted_parameters,
185     SourceStream* correction,
186     SourceStreamSet* corrected_parameters) {
187   return SubpatchStreamSets(predicted_parameters,
188                             correction,
189                             corrected_parameters,
190                             &corrected_parameters_storage_);
191 }
192
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);
203     if (status != C_OK)
204       return status;
205     if (!single_parameters.Empty())
206       return C_STREAM_NOT_CONSUMED;
207     if (!transformed_elements->WriteSet(&single_transformed_element))
208       return C_STREAM_ERROR;
209   }
210
211   if (!parameters->Empty())
212     return C_STREAM_NOT_CONSUMED;
213   return C_OK;
214 }
215
216 Status EnsemblePatchApplication::SubpatchTransformedElements(
217     SinkStreamSet* predicted_elements,
218     SourceStream* correction,
219     SourceStreamSet* corrected_elements) {
220   return SubpatchStreamSets(predicted_elements,
221                             correction,
222                             corrected_elements,
223                             &corrected_elements_storage_);
224 }
225
226 Status EnsemblePatchApplication::TransformDown(
227     SourceStreamSet* transformed_elements,
228     SinkStream* basic_elements) {
229   // Construct blob of original input followed by reformed elements.
230
231   if (!basic_elements->Reserve(final_patch_input_size_prediction_)) {
232     return C_STREAM_ERROR;
233   }
234
235   // The original input:
236   if (!basic_elements->Write(base_region_.start(), base_region_.length()))
237     return C_STREAM_ERROR;
238
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,
244                                          basic_elements);
245     if (status != C_OK)
246       return status;
247     if (!single_corrected_element.Empty())
248       return C_STREAM_NOT_CONSUMED;
249   }
250
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();
256
257   return C_OK;
258 }
259
260 Status EnsemblePatchApplication::SubpatchFinalOutput(
261     SourceStream* original,
262     SourceStream* correction,
263     SinkStream* corrected_ensemble) {
264   Status delta_status = ApplySimpleDelta(original, correction,
265                                          corrected_ensemble);
266   if (delta_status != C_OK)
267     return delta_status;
268
269   if (CalculateCrc(corrected_ensemble->Buffer(),
270                    corrected_ensemble->Length()) != target_checksum_)
271     return C_BAD_ENSEMBLE_CRC;
272
273   return C_OK;
274 }
275
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;
284
285   SourceStream prediction;
286   prediction.Init(linearized_predicted_items);
287
288   Status status = ApplySimpleDelta(&prediction,
289                                    correction,
290                                    corrected_items_storage);
291   if (status != C_OK)
292     return status;
293
294   if (!corrected_items->Init(corrected_items_storage->Buffer(),
295                              corrected_items_storage->Length()))
296     return C_STREAM_ERROR;
297
298   return C_OK;
299 }
300
301 Status ApplyEnsemblePatch(SourceStream* base,
302                           SourceStream* patch,
303                           SinkStream* output) {
304   Status status;
305   EnsemblePatchApplication patch_process;
306
307   status = patch_process.ReadHeader(patch);
308   if (status != C_OK)
309     return status;
310
311   status = patch_process.InitBase(Region(base->Buffer(), base->Remaining()));
312   if (status != C_OK)
313     return status;
314
315   status = patch_process.ValidateBase();
316   if (status != C_OK)
317     return status;
318
319   // The rest of the patch stream is a StreamSet.
320   SourceStreamSet patch_streams;
321   patch_streams.Init(patch);
322
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);
327
328   status = patch_process.ReadInitialParameters(transformation_descriptions);
329   if (status != C_OK)
330     return status;
331
332   SinkStreamSet predicted_parameters;
333   status = patch_process.PredictTransformParameters(&predicted_parameters);
334   if (status != C_OK)
335     return status;
336
337   SourceStreamSet corrected_parameters;
338   status = patch_process.SubpatchTransformParameters(&predicted_parameters,
339                                                      parameter_correction,
340                                                      &corrected_parameters);
341   if (status != C_OK)
342     return status;
343
344   SinkStreamSet transformed_elements;
345   status = patch_process.TransformUp(&corrected_parameters,
346                                      &transformed_elements);
347   if (status != C_OK)
348     return status;
349
350   SourceStreamSet corrected_transformed_elements;
351   status = patch_process.SubpatchTransformedElements(
352           &transformed_elements,
353           transformed_elements_correction,
354           &corrected_transformed_elements);
355   if (status != C_OK)
356     return status;
357
358   SinkStream original_ensemble_and_corrected_base_elements;
359   status = patch_process.TransformDown(
360       &corrected_transformed_elements,
361       &original_ensemble_and_corrected_base_elements);
362   if (status != C_OK)
363     return status;
364
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);
369   if (status != C_OK)
370     return status;
371
372   return C_OK;
373 }
374
375 Status ApplyEnsemblePatch(base::File old_file,
376                           base::File patch_file,
377                           base::File new_file) {
378   base::MemoryMappedFile patch_file_mem;
379   if (!patch_file_mem.Initialize(std::move(patch_file)))
380     return C_READ_OPEN_ERROR;
381
382   // 'Dry-run' the first step of the patch process to validate format of header.
383   SourceStream patch_header_stream;
384   patch_header_stream.Init(patch_file_mem.data(), patch_file_mem.length());
385   EnsemblePatchApplication patch_process;
386   Status status = patch_process.ReadHeader(&patch_header_stream);
387   if (status != C_OK)
388     return status;
389
390   // Read the old_file.
391   base::MemoryMappedFile old_file_mem;
392   if (!old_file_mem.Initialize(std::move(old_file)))
393     return C_READ_ERROR;
394
395   // Apply patch on streams.
396   SourceStream old_source_stream;
397   SourceStream patch_source_stream;
398   old_source_stream.Init(old_file_mem.data(), old_file_mem.length());
399   patch_source_stream.Init(patch_file_mem.data(), patch_file_mem.length());
400   SinkStream new_sink_stream;
401   status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream,
402                               &new_sink_stream);
403   if (status != C_OK)
404     return status;
405
406   // Write the patched data to |new_file_name|.
407   int written = new_file.Write(
408       0,
409       reinterpret_cast<const char*>(new_sink_stream.Buffer()),
410       static_cast<int>(new_sink_stream.Length()));
411   if (written == -1)
412     return C_WRITE_OPEN_ERROR;
413   if (static_cast<size_t>(written) != new_sink_stream.Length())
414     return C_WRITE_ERROR;
415
416   return C_OK;
417 }
418
419 Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name,
420                           const base::FilePath::CharType* patch_file_name,
421                           const base::FilePath::CharType* new_file_name) {
422   Status result = ApplyEnsemblePatch(
423       base::File(base::FilePath(old_file_name),
424                  base::File::FLAG_OPEN | base::File::FLAG_READ |
425                      base::File::FLAG_WIN_SHARE_DELETE),
426       base::File(base::FilePath(patch_file_name),
427                  base::File::FLAG_OPEN | base::File::FLAG_READ |
428                      base::File::FLAG_WIN_SHARE_DELETE),
429       base::File(base::FilePath(new_file_name),
430                  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
431                      base::File::FLAG_WIN_EXCLUSIVE_WRITE |
432                      base::File::FLAG_WIN_SHARE_DELETE));
433   if (result != C_OK)
434     base::DeleteFile(base::FilePath(new_file_name));
435   return result;
436 }
437
438 }  // namespace courgette