Home | History | Annotate | Download | only in courgette
      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.
      4 
      5 // The main idea in Courgette is to do patching *under a tranformation*.  The
      6 // input is transformed into a new representation, patching occurs in the new
      7 // repesentation, and then the tranform is reversed to get the patched data.
      8 //
      9 // The idea is applied to pieces (or 'Elements') of the whole (or 'Ensemble').
     10 // Each of the elements has to go through the same set of steps in lock-step,
     11 // but there may be many different kinds of elements, which have different
     12 // transformation.
     13 //
     14 // This file declares all the main types involved in creating and applying a
     15 // patch with this structure.
     16 
     17 #ifndef COURGETTE_ENSEMBLE_H_
     18 #define COURGETTE_ENSEMBLE_H_
     19 
     20 #include <vector>
     21 #include <string>
     22 
     23 #include "base/basictypes.h"
     24 
     25 #include "courgette/courgette.h"
     26 #include "courgette/region.h"
     27 #include "courgette/streams.h"
     28 
     29 namespace courgette {
     30 
     31 // Forward declarations:
     32 class Ensemble;
     33 
     34 // An Element is a region of an Ensemble with an identifyable kind.
     35 //
     36 class Element {
     37  public:
     38   Element(ExecutableType kind,
     39           Ensemble* ensemble,
     40           const Region& region);
     41 
     42   virtual ~Element();
     43 
     44   ExecutableType kind() const { return kind_; }
     45   const Region& region() const { return region_; }
     46 
     47   // The name is used only for debugging and logging.
     48   virtual std::string Name() const;
     49 
     50   // Returns the byte position of this Element relative to the start of
     51   // containing Ensemble.
     52   size_t offset_in_ensemble() const;
     53 
     54  private:
     55   ExecutableType kind_;
     56   Ensemble* ensemble_;
     57   Region region_;
     58 
     59   DISALLOW_COPY_AND_ASSIGN(Element);
     60 };
     61 
     62 
     63 class Ensemble {
     64  public:
     65   Ensemble(const Region& region, const char* name)
     66       : region_(region), name_(name) {}
     67   ~Ensemble();
     68 
     69   const Region& region() const { return region_; }
     70   const std::string& name() const { return name_; }
     71 
     72   // Scans the region to find Elements within the region().
     73   Status FindEmbeddedElements();
     74 
     75   // Returns the elements found by 'FindEmbeddedElements'.
     76   const std::vector<Element*>& elements() const { return elements_; }
     77 
     78 
     79  private:
     80   Region region_;       // The memory, owned by caller, containing the
     81                         // Ensemble's data.
     82   std::string name_;    // A debugging/logging name for the Ensemble.
     83 
     84   std::vector<Element*> elements_;        // Embedded elements discovered.
     85   std::vector<Element*> owned_elements_;  // For deallocation.
     86 
     87   DISALLOW_COPY_AND_ASSIGN(Ensemble);
     88 };
     89 
     90 inline size_t Element::offset_in_ensemble() const {
     91   return region().start() - ensemble_->region().start();
     92 }
     93 
     94 // The 'CourgettePatchFile' is class is a 'namespace' for the constants that
     95 // appear in a Courgette patch file.
     96 struct CourgettePatchFile {
     97   //
     98   // The Courgette patch format interleaves the data for N embedded Elements.
     99   //
    100   // Format of a patch file:
    101   //  header:
    102   //    magic
    103   //    version
    104   //    source-checksum
    105   //    target-checksum
    106   //    final-patch-input-size (an allocation hint)
    107   //  multiple-streams:
    108   //    stream 0:
    109   //      number-of-transformed-elements (N) - varint32
    110   //      transformation-1-method-id
    111   //      transformation-2-method-id
    112   //      ...
    113   //      transformation-1-initial-parameters
    114   //      transformation-2-initial-parameters
    115   //      ...
    116   //    stream 1:
    117   //      correction:
    118   //        transformation-1-parameters
    119   //        transformation-2-parameters
    120   //        ...
    121   //    stream 2:
    122   //      correction:
    123   //        transformed-element-1
    124   //        transformed-element-2
    125   //        ...
    126   //    stream 3:
    127   //      correction:
    128   //        base-file
    129   //        element-1
    130   //        element-2
    131   //        ...
    132 
    133   static const uint32 kMagic = 'C' | ('o' << 8) | ('u' << 16);
    134 
    135   static const uint32 kVersion = 20110216;
    136 };
    137 
    138 // For any transform you would implement both a TransformationPatcher and a
    139 // TransformationPatchGenerator.
    140 //
    141 // TransformationPatcher is the interface which abstracts out the actual
    142 // transformation used on an Element.  The patching itself happens outside the
    143 // actions of a TransformationPatcher.  There are four steps.
    144 //
    145 // The first step is an Init step.  The parameters to the Init step identify the
    146 // element, for example, range of locations within the original ensemble that
    147 // correspond to the element.
    148 //
    149 // PredictTransformParameters, explained below.
    150 //
    151 // The two final steps are 'Transform' - to transform the element into a new
    152 // representation, and to 'Reform' - to transform from the new representation
    153 // back to the original form.
    154 //
    155 // The Transform step takes some parameters.  This allows the transform to be
    156 // customized to the particular element, or to receive some assistance in the
    157 // analysis required to perform the transform.  The transform parameters might
    158 // be extensive but mostly predicable, so preceeding Transform is a
    159 // PredictTransformParameters step.
    160 //
    161 class TransformationPatcher {
    162  public:
    163   virtual ~TransformationPatcher() {}
    164 
    165   // First step: provides parameters for the patching.  This would at a minimum
    166   // identify the element within the ensemble being patched.
    167   virtual Status Init(SourceStream* parameter_stream) = 0;
    168 
    169   // Second step: predicts transform parameters.
    170   virtual Status PredictTransformParameters(
    171       SinkStreamSet* predicted_parameters) = 0;
    172 
    173   // Third step: transforms element from original representation into alternate
    174   // representation.
    175   virtual Status Transform(SourceStreamSet* corrected_parameters,
    176                            SinkStreamSet* transformed_element) = 0;
    177 
    178   // Final step: transforms element back from alternate representation into
    179   // original representation.
    180   virtual Status Reform(SourceStreamSet* transformed_element,
    181                         SinkStream* reformed_element) = 0;
    182 };
    183 
    184 // TransformationPatchGenerator is the interface which abstracts out the actual
    185 // transformation used (and adjustment used) when differentially compressing one
    186 // Element from the |new_ensemble| against a corresponding element in the
    187 // |old_ensemble|.
    188 //
    189 // This is not a pure interface.  There is a small amount of inheritance
    190 // implementation for the fields and actions common to all
    191 // TransformationPatchGenerators.
    192 //
    193 // When TransformationPatchGenerator is subclassed, there will be a
    194 // corresponding subclass of TransformationPatcher.
    195 //
    196 class TransformationPatchGenerator {
    197  public:
    198   TransformationPatchGenerator(Element* old_element,
    199                                Element* new_element,
    200                                TransformationPatcher* patcher);
    201 
    202   virtual ~TransformationPatchGenerator();
    203 
    204   // Returns the TransformationMethodId that identies this transformation.
    205   virtual ExecutableType Kind() = 0;
    206 
    207   // Writes the parameters that will be passed to TransformationPatcher::Init.
    208   virtual Status WriteInitialParameters(SinkStream* parameter_stream) = 0;
    209 
    210   // Predicts the transform parameters for the |old_element|.  This must match
    211   // exactly the output that will be produced by the PredictTransformParameters
    212   // method of the corresponding subclass of TransformationPatcher.  This method
    213   // is not pure. The default implementation delegates to the patcher to
    214   // guarantee matching output.
    215   virtual Status PredictTransformParameters(SinkStreamSet* prediction);
    216 
    217   // Writes the desired parameters for the transform of the old element from the
    218   // file representation to the alternate representation.
    219   virtual Status CorrectedTransformParameters(SinkStreamSet* parameters) = 0;
    220 
    221   // Writes both |old_element| and |new_element| in the new representation.
    222   // |old_corrected_parameters| will match the |corrected_parameters| passed to
    223   // the Transform method of the corresponding sublcass of
    224   // TransformationPatcher.
    225   //
    226   // The output written to |old_transformed_element| must match exactly the
    227   // output written by the Transform method of the corresponding subclass of
    228   // TransformationPatcher.
    229   virtual Status Transform(SourceStreamSet* old_corrected_parameters,
    230                            SinkStreamSet* old_transformed_element,
    231                            SinkStreamSet* new_transformed_element) = 0;
    232 
    233   // Transforms the new transformed_element back from the alternate
    234   // representation into the original file format.  This must match exactly the
    235   // output that will be produced by the corresponding subclass of
    236   // TransformationPatcher::Reform.  This method is not pure. The default
    237   // implementation delegates to the patcher.
    238   virtual Status Reform(SourceStreamSet* transformed_element,
    239                         SinkStream* reformed_element);
    240 
    241  protected:
    242   Element* old_element_;
    243   Element* new_element_;
    244   TransformationPatcher* patcher_;
    245 };
    246 
    247 }  // namespace
    248 #endif  // COURGETTE_ENSEMBLE_H_
    249