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