diff options
Diffstat (limited to 'courgette/ensemble.h')
-rw-r--r-- | courgette/ensemble.h | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/courgette/ensemble.h b/courgette/ensemble.h new file mode 100644 index 0000000..6a58cb0 --- /dev/null +++ b/courgette/ensemble.h @@ -0,0 +1,257 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The main idea in Courgette is to do patching *under a tranformation*. The +// input is transformed into a new representation, patching occurs in the new +// repesentation, and then the tranform is reversed to get the patched data. +// +// The idea is applied to pieces (or 'Elements') of the whole (or 'Ensemble'). +// Each of the elements has to go through the same set of steps in lock-step, +// but there may be many different kinds of elements, which have different +// transformation. +// +// This file declares all the main types involved in creating and applying a +// patch with this structure. + +#ifndef COURGETTE_ENSEMBLE_H_ +#define COURGETTE_ENSEMBLE_H_ + +#include <vector> +#include <string> + +#include "base/basictypes.h" + +#include "courgette/courgette.h" +#include "courgette/region.h" +#include "courgette/streams.h" + +namespace courgette { + +// Forward declarations: +class Ensemble; +class PEInfo; + +// An Element is a region of an Ensemble with an identifyable kind. +// +class Element { + public: + enum Kind { WIN32_X86_WITH_CODE, WIN32_NOCODE }; + + virtual ~Element() {} + + Kind kind() const { return kind_; } + const Region& region() const { return region_; } + + // The name is used only for debugging and logging. + virtual std::string Name() const; + + // Returns the byte position of this Element relative to the start of + // containing Ensemble. + size_t offset_in_ensemble() const; + + // Some subclasses of Element might have a PEInfo. + virtual PEInfo* GetPEInfo() const { return NULL; } + + protected: + Element(Kind kind, Ensemble* ensemble, const Region& region); + + private: + Kind kind_; + Ensemble* ensemble_; + Region region_; + + DISALLOW_COPY_AND_ASSIGN(Element); +}; + + +class Ensemble { + public: + Ensemble(const Region& region, const char* name) + : region_(region), name_(name) {} + ~Ensemble(); + + const Region& region() const { return region_; } + const std::string& name() const { return name_; } + + // Scans the region to find Elements within the region(). + Status FindEmbeddedElements(); + + // Returns the elements found by 'FindEmbeddedElements'. + const std::vector<Element*>& elements() const { return elements_; } + + + private: + Region region_; // The memory, owned by caller, containing the + // Ensemble's data. + std::string name_; // A debugging/logging name for the Ensemble. + + std::vector<Element*> elements_; // Embedded elements discovered. + std::vector<Element*> owned_elements_; // For deallocation. + + DISALLOW_COPY_AND_ASSIGN(Ensemble); +}; + +inline size_t Element::offset_in_ensemble() const { + return region().start() - ensemble_->region().start(); +} + +// The 'CourgettePatchFile' is class is a 'namespace' for the constants that +// appear in a Courgette patch file. +struct CourgettePatchFile { + // + // The Courgette patch format interleaves the data for N embedded Elements. + // + // Format of a patch file: + // header: + // magic + // version + // source-checksum + // target-checksum + // multiple-streams: + // stream 0: + // number-of-transformed-elements (N) - varint32 + // transformation-1-method-id + // transformation-2-method-id + // ... + // transformation-1-initial-parameters + // transformation-2-initial-parameters + // ... + // stream 1: + // correction: + // transformation-1-parameters + // transformation-2-parameters + // ... + // stream 2: + // correction: + // transformed-element-1 + // transformed-element-2 + // ... + // stream 3: + // correction: + // base-file + // element-1 + // element-2 + // ... + + static const uint32 kMagic = 'C' | ('o' << 8) | ('u' << 16); + + static const uint32 kVersion = 20090320; + + // Transformation method IDs. + enum TransformationMethodId { + T_COURGETTE_WIN32_X86 = 1, // Windows 32 bit 'Portable Executable' x86. + }; +}; + +// For any transform you would implement both a TransformationPatcher and a +// TransformationPatchGenerator. +// +// TransformationPatcher is the interface which abstracts out the actual +// transformation used on an Element. The patching itself happens outside the +// actions of a TransformationPatcher. There are four steps. +// +// The first step is an Init step. The parameters to the Init step identify the +// element, for example, range of locations within the original ensemble that +// correspond to the element. +// +// PredictTransformParameters, explained below. +// +// The two final steps are 'Transform' - to transform the element into a new +// representation, and to 'Reform' - to transform from the new representation +// back to the original form. +// +// The Transform step takes some parameters. This allows the transform to be +// customized to the particular element, or to receive some assistance in the +// analysis required to perform the transform. The transform parameters might +// be extensive but mostly predicable, so preceeding Transform is a +// PredictTransformParameters step. +// +class TransformationPatcher { + public: + virtual ~TransformationPatcher() {} + + // First step: provides parameters for the patching. This would at a minimum + // identify the element within the ensemble being patched. + virtual Status Init(SourceStream* parameter_stream) = 0; + + // Second step: predicts transform parameters. + virtual Status PredictTransformParameters( + SinkStreamSet* predicted_parameters) = 0; + + // Third step: transforms element from original representation into alternate + // representation. + virtual Status Transform(SourceStreamSet* corrected_parameters, + SinkStreamSet* transformed_element) = 0; + + // Final step: transforms element back from alternate representation into + // original representation. + virtual Status Reform(SourceStreamSet* transformed_element, + SinkStream* reformed_element) = 0; +}; + +// TransformationPatchGenerator is the interface which abstracts out the actual +// transformation used (and adjustment used) when differentially compressing one +// Element from the |new_ensemble| against a corresponding element in the +// |old_ensemble|. +// +// This is not a pure interface. There is a small amount of inheritance +// implementation for the fields and actions common to all +// TransformationPatchGenerators. +// +// When TransformationPatchGenerator is subclassed, there will be a +// corresponding subclass of TransformationPatcher. +// +class TransformationPatchGenerator { + public: + TransformationPatchGenerator(Element* old_element, + Element* new_element, + TransformationPatcher* patcher); + + virtual ~TransformationPatchGenerator(); + + // Returns the TransformationMethodId that identies this transformation. + virtual CourgettePatchFile::TransformationMethodId Kind() = 0; + + // Writes the parameters that will be passed to TransformationPatcher::Init. + virtual Status WriteInitialParameters(SinkStream* parameter_stream) = 0; + + // Predicts the transform parameters for the |old_element|. This must match + // exactly the output that will be produced by the PredictTransformParameters + // method of the corresponding subclass of TransformationPatcher. This method + // is not pure. The default implementation delegates to the patcher to + // guarantee matching output. + virtual Status PredictTransformParameters(SinkStreamSet* prediction); + + // Writes the desired parameters for the transform of the old element from the + // file representation to the alternate representation. + virtual Status CorrectedTransformParameters(SinkStreamSet* parameters) = 0; + + // Writes both |old_element| and |new_element| in the new representation. + // |old_corrected_parameters| will match the |corrected_parameters| passed to + // the Transform method of the corresponding sublcass of + // TransformationPatcher. + // + // The output written to |old_transformed_element| must match exactly the + // output written by the Transform method of the corresponding subclass of + // TransformationPatcher. + virtual Status Transform(SourceStreamSet* old_corrected_parameters, + SinkStreamSet* old_transformed_element, + SinkStreamSet* new_transformed_element) = 0; + + // Transforms the new transformed_element back from the alternate + // representation into the original file format. This must match exactly the + // output that will be produced by the corresponding subclass of + // TransformationPatcher::Reform. This method is not pure. The default + // implementation delegates to the patcher. + virtual Status Reform(SourceStreamSet* transformed_element, + SinkStream* reformed_element); + + protected: + Element* old_element_; + Element* new_element_; + TransformationPatcher* patcher_; +}; + +} // namespace +#endif // COURGETTE_ENSEMBLE_H_ |