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