140 lines
4.3 KiB
C++
140 lines
4.3 KiB
C++
// Copyright 2017 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.
|
|
|
|
#ifndef COMPONENTS_ZUCCHINI_PATCH_UTILS_H_
|
|
#define COMPONENTS_ZUCCHINI_PATCH_UTILS_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <iterator>
|
|
#include <type_traits>
|
|
|
|
#include "components/zucchini/image_utils.h"
|
|
#include "components/zucchini/version_info.h"
|
|
|
|
namespace zucchini {
|
|
|
|
// A Zucchini 'ensemble' patch is the concatenation of a patch header with a
|
|
// list of patch 'elements', each containing data for patching individual
|
|
// elements.
|
|
|
|
// Supported by MSVC, g++, and clang++. Ensures no gaps in packing.
|
|
#pragma pack(push, 1)
|
|
|
|
// Header for a Zucchini patch, found at the beginning of an ensemble patch.
|
|
struct PatchHeader {
|
|
// Magic signature at the beginning of a Zucchini patch file.
|
|
enum : uint32_t { kMagic = 'Z' | ('u' << 8) | ('c' << 16) | ('c' << 24) };
|
|
|
|
uint32_t magic = 0;
|
|
uint16_t major_version = kInvalidVersion;
|
|
uint16_t minor_version = kInvalidVersion;
|
|
uint32_t old_size = 0;
|
|
uint32_t old_crc = 0;
|
|
uint32_t new_size = 0;
|
|
uint32_t new_crc = 0;
|
|
};
|
|
|
|
// Sanity check.
|
|
static_assert(sizeof(PatchHeader) == 24, "PatchHeader must be 24 bytes");
|
|
|
|
// Header for a patch element, found at the beginning of every patch element.
|
|
struct PatchElementHeader {
|
|
uint32_t old_offset;
|
|
uint32_t old_length;
|
|
uint32_t new_offset;
|
|
uint32_t new_length;
|
|
uint32_t exe_type; // ExecutableType.
|
|
uint16_t version = kInvalidVersion;
|
|
};
|
|
|
|
// Sanity check.
|
|
static_assert(sizeof(PatchElementHeader) == 22,
|
|
"PatchElementHeader must be 22 bytes");
|
|
|
|
#pragma pack(pop)
|
|
|
|
// Descibes a raw FIX operation.
|
|
struct RawDeltaUnit {
|
|
offset_t copy_offset; // Offset in copy regions.
|
|
int8_t diff; // Bytewise difference.
|
|
};
|
|
|
|
// A Zucchini patch contains data streams encoded using varint format to reduce
|
|
// uncompressed size.
|
|
|
|
// Writes |value| as a varint in |dst| and returns an iterator pointing beyond
|
|
// the written region. |dst| is assumed to hold enough space. Typically, this
|
|
// will write to a vector using back insertion, e.g.:
|
|
// EncodeVarUInt(value, std::back_inserter(vector));
|
|
template <class T, class It>
|
|
It EncodeVarUInt(T value, It dst) {
|
|
static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
|
|
|
|
while (value >= 0x80) {
|
|
*dst++ = static_cast<uint8_t>(value) | 0x80;
|
|
value >>= 7;
|
|
}
|
|
*dst++ = static_cast<uint8_t>(value);
|
|
return dst;
|
|
}
|
|
|
|
// Same as EncodeVarUInt(), but for signed values.
|
|
template <class T, class It>
|
|
It EncodeVarInt(T value, It dst) {
|
|
static_assert(std::is_signed<T>::value, "Value type must be signed");
|
|
|
|
using unsigned_value_type = typename std::make_unsigned<T>::type;
|
|
if (value < 0)
|
|
return EncodeVarUInt((unsigned_value_type(~value) << 1) | 1, dst);
|
|
else
|
|
return EncodeVarUInt(unsigned_value_type(value) << 1, dst);
|
|
}
|
|
|
|
// Tries to read a varint unsigned integer from |[first, last)|. If
|
|
// succesful, writes result into |value| and returns the number of bytes
|
|
// read from |[first, last)|. Otherwise returns 0.
|
|
template <class T, class It>
|
|
typename std::iterator_traits<It>::difference_type DecodeVarUInt(It first,
|
|
It last,
|
|
T* value) {
|
|
static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
|
|
|
|
uint8_t sh = 0;
|
|
T val = 0;
|
|
for (auto it = first; it != last;) {
|
|
val |= T(*it & 0x7F) << sh;
|
|
if (*(it++) < 0x80) {
|
|
*value = val;
|
|
return it - first;
|
|
}
|
|
sh += 7;
|
|
if (sh >= sizeof(T) * 8) // Overflow!
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Same as DecodeVarUInt(), but for signed values.
|
|
template <class T, class It>
|
|
typename std::iterator_traits<It>::difference_type DecodeVarInt(It first,
|
|
It last,
|
|
T* value) {
|
|
static_assert(std::is_signed<T>::value, "Value type must be signed");
|
|
|
|
typename std::make_unsigned<T>::type tmp = 0;
|
|
auto res = DecodeVarUInt(first, last, &tmp);
|
|
if (res) {
|
|
if (tmp & 1)
|
|
*value = ~static_cast<T>(tmp >> 1);
|
|
else
|
|
*value = static_cast<T>(tmp >> 1);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
} // namespace zucchini
|
|
|
|
#endif // COMPONENTS_ZUCCHINI_PATCH_UTILS_H_
|