123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- // 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_
|