You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
3.9 KiB
99 lines
3.9 KiB
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef _BSDIFF_ENDSLEY_PATCH_WRITER_H_
|
|
#define _BSDIFF_ENDSLEY_PATCH_WRITER_H_
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "bsdiff/compressor_interface.h"
|
|
#include "bsdiff/constants.h"
|
|
#include "bsdiff/patch_writer_interface.h"
|
|
|
|
namespace bsdiff {
|
|
|
|
// A PatchWriterInterface class compatible with the format used by Android Play
|
|
// Store's bsdiff implementation, which is based on Matthew Endsley's bsdiff
|
|
// implementation. See https://github.com/mendsley/bsdiff for the original
|
|
// implementation of this format. See also Google's APK patch size estimator for
|
|
// more information on the file-by-file format used by Play Store:
|
|
// https://github.com/googlesamples/apk-patch-size-estimator
|
|
|
|
// This format, identified by the "ENDSLEY/BSDIFF43" magic string, uses a single
|
|
// stream with the control entries, diff data and extra data interleaved. After
|
|
// the header, each Control Entry is stored in 24 bytes followed by the diff
|
|
// stream data for that entry only, and then followed by the extra stream data
|
|
// for that entry only. The format doesn't handle the compression of the data,
|
|
// instead, the whole file (including the magic string) is compressed with any
|
|
// compression algorithm.
|
|
|
|
// This format is easier to parse and allows the patch to be streamed, but by
|
|
// mixing the diff and extra data into the same compression context offers a
|
|
// slightly worse compression ratio (about 3.5% compared to upstream's format).
|
|
|
|
class EndsleyPatchWriter : public PatchWriterInterface {
|
|
public:
|
|
// Create the patch writer that will write the data to the passed vector
|
|
// |patch|, resizing it as needed. The |patch| vector must be valid until
|
|
// Close() is called or this patch is destroyed. The data in |patch| will be
|
|
// compressed using the compressor type |type|.
|
|
EndsleyPatchWriter(std::vector<uint8_t>* patch,
|
|
CompressorType type,
|
|
int brotli_quality)
|
|
: patch_(patch),
|
|
compressor_type_(type),
|
|
brotli_quality_(brotli_quality) {}
|
|
|
|
// PatchWriterInterface overrides.
|
|
bool Init(size_t new_size) override;
|
|
bool WriteDiffStream(const uint8_t* data, size_t size) override;
|
|
bool WriteExtraStream(const uint8_t* data, size_t size) override;
|
|
bool AddControlEntry(const ControlEntry& entry) override;
|
|
bool Close() override;
|
|
|
|
private:
|
|
// Emit at the end of the |patch_| vector the passed control entry.
|
|
void EmitControlEntry(const ControlEntry& entry);
|
|
|
|
// Emit at the end of the |patch_| vector the passed buffer.
|
|
void EmitBuffer(const uint8_t* data, size_t size);
|
|
|
|
// Flush as much as possible of the pending data.
|
|
void Flush();
|
|
|
|
// The vector we are writing to, owned by the caller.
|
|
std::vector<uint8_t>* patch_;
|
|
|
|
// The compressor type to use and its quality (if any).
|
|
CompressorType compressor_type_;
|
|
int brotli_quality_;
|
|
|
|
std::unique_ptr<CompressorInterface> compressor_;
|
|
|
|
// The pending diff and extra data to be encoded in the file. These vectors
|
|
// would not be used whenever is possible to the data directly to the patch_
|
|
// vector; namely when the control, diff and extra stream data are provided in
|
|
// that order for each control entry.
|
|
std::vector<uint8_t> diff_data_;
|
|
std::vector<uint8_t> extra_data_;
|
|
std::vector<ControlEntry> control_;
|
|
|
|
// Defined as the sum of all the diff_size and extra_size values in
|
|
// |control_|. This is used to determine whether it is worth Flushing the
|
|
// pending data.
|
|
size_t pending_control_data_{0};
|
|
|
|
// Number of bytes in the diff and extra stream that are pending in the
|
|
// last control entry encoded in the |patch_|. If both are zero the last
|
|
// control entry was completely emitted.
|
|
size_t pending_diff_{0};
|
|
size_t pending_extra_{0};
|
|
};
|
|
|
|
} // namespace bsdiff
|
|
|
|
#endif // _BSDIFF_ENDSLEY_PATCH_WRITER_H_
|