blob: 77cf2f3411d275822631ed7d513d8dcd22e2563b [file] [log] [blame]
Samuel Huang06f1ae92018-03-13 18:19:34 +00001// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef COMPONENTS_ZUCCHINI_PATCH_UTILS_H_
6#define COMPONENTS_ZUCCHINI_PATCH_UTILS_H_
7
8#include <stdint.h>
9
10#include <iterator>
11#include <type_traits>
12
13#include "components/zucchini/image_utils.h"
14
15namespace zucchini {
16
17// Constants that appear inside a patch.
18enum class PatchType : uint32_t {
19 // Patch contains a single raw element, corresponding to an element match that
20 // covers the entire images, and with ExecutableType::kExeTypeNoOp.
21 kRawPatch = 0,
22
23 // Patch contains a single executable element, corresponding to an element
24 // match that covers the entire images.
25 kSinglePatch = 1,
26
27 // Patch contains multiple raw and/or executable elements.
28 kEnsemblePatch = 2,
29
30 // Used when type is uninitialized.
31 kUnrecognisedPatch
32};
33
34// A Zucchini 'ensemble' patch is the concatenation of a patch header with a
35// list of patch 'elements', each containing data for patching individual
36// elements.
37
38// Supported by MSVC, g++, and clang++. Ensures no gaps in packing.
39#pragma pack(push, 1)
40
41// Header for a Zucchini patch, found at the beginning of an ensemble patch.
42struct PatchHeader {
43 // Magic signature at the beginning of a Zucchini patch file.
44 enum : uint32_t { kMagic = 'Z' | ('u' << 8) | ('c' << 16) };
45
46 uint32_t magic = 0;
47 uint32_t old_size = 0;
48 uint32_t old_crc = 0;
49 uint32_t new_size = 0;
50 uint32_t new_crc = 0;
51};
52
53// Sanity check.
54static_assert(sizeof(PatchHeader) == 20, "PatchHeader is 20 bytes");
55
56// Header for a patch element, found at the beginning of every patch element.
57struct PatchElementHeader {
58 uint32_t old_offset;
59 uint32_t new_offset;
60 uint32_t old_length;
61 uint32_t new_length;
62 uint32_t exe_type;
63};
64
65// Sanity check.
66static_assert(sizeof(PatchElementHeader) == 20,
67 "PatchElementHeader is 28 bytes");
68
69#pragma pack(pop)
70
71// Descibes a raw FIX operation.
72struct RawDeltaUnit {
73 offset_t copy_offset; // Offset in copy regions.
74 int8_t diff; // Bytewise difference.
75};
76
77// A Zucchini patch contains data streams encoded using varint format to reduce
78// uncompressed size.
79
80// Writes |value| as a varint in |dst| and returns an iterator pointing beyond
81// the written region. |dst| is assumed to hold enough space. Typically, this
82// will write to a vector using back insertion, e.g.:
83// EncodeVarUInt(value, std::back_inserter(vector));
84template <class T, class It>
85It EncodeVarUInt(T value, It dst) {
86 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
87
88 while (value >= 0x80) {
89 *dst++ = static_cast<uint8_t>(value) | 0x80;
90 value >>= 7;
91 }
92 *dst++ = static_cast<uint8_t>(value);
93 return dst;
94}
95
96// Same as EncodeVarUInt(), but for signed values.
97template <class T, class It>
98It EncodeVarInt(T value, It dst) {
99 static_assert(std::is_signed<T>::value, "Value type must be signed");
100
101 using unsigned_value_type = typename std::make_unsigned<T>::type;
102 if (value < 0)
103 return EncodeVarUInt((unsigned_value_type(~value) << 1) | 1, dst);
104 else
105 return EncodeVarUInt(unsigned_value_type(value) << 1, dst);
106}
107
108// Tries to read a varint unsigned integer from |[first, last)|. If
109// succesful, writes result into |value| and returns the number of bytes
110// read from |[first, last)|. Otherwise returns 0.
111template <class T, class It>
112typename std::iterator_traits<It>::difference_type DecodeVarUInt(It first,
113 It last,
114 T* value) {
115 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
116
117 uint8_t sh = 0;
118 T val = 0;
119 for (auto it = first; it != last;) {
120 val |= T(*it & 0x7F) << sh;
121 if (*(it++) < 0x80) {
122 *value = val;
123 return it - first;
124 }
125 sh += 7;
126 if (sh >= sizeof(T) * 8) // Overflow!
127 return 0;
128 }
129 return 0;
130}
131
132// Same as DecodeVarUInt(), but for signed values.
133template <class T, class It>
134typename std::iterator_traits<It>::difference_type DecodeVarInt(It first,
135 It last,
136 T* value) {
137 static_assert(std::is_signed<T>::value, "Value type must be signed");
138
139 typename std::make_unsigned<T>::type tmp = 0;
140 auto res = DecodeVarUInt(first, last, &tmp);
141 if (res) {
142 if (tmp & 1)
143 *value = ~static_cast<T>(tmp >> 1);
144 else
145 *value = static_cast<T>(tmp >> 1);
146 }
147 return res;
148}
149
150} // namespace zucchini
151
152#endif // COMPONENTS_ZUCCHINI_PATCH_UTILS_H_