blob: 822fedc587ab6946b23cb0e7e5ea7ef05b2fe0f3 [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
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000017// A change in major version indicates breaking changes such that a patch
18// definitely cannot be applied by a zucchini binary whose major version doesn't
19// match.
20enum : uint16_t { kMajorVersion = 1 };
21// A change in minor version indicates possibly breaking changes at the element
22// level, such that it may not be possible to apply a patch whose minor version
23// doesn't match this version. To determine if a given patch may be applied with
24// this version, VerifyPatch() should be called.
25enum : uint16_t { kMinorVersion = 0 };
26enum : uint16_t { kInvalidVersion = 0xffff };
27
Samuel Huang06f1ae92018-03-13 18:19:34 +000028// A Zucchini 'ensemble' patch is the concatenation of a patch header with a
29// list of patch 'elements', each containing data for patching individual
30// elements.
31
32// Supported by MSVC, g++, and clang++. Ensures no gaps in packing.
33#pragma pack(push, 1)
34
35// Header for a Zucchini patch, found at the beginning of an ensemble patch.
36struct PatchHeader {
37 // Magic signature at the beginning of a Zucchini patch file.
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000038 enum : uint32_t { kMagic = 'Z' | ('u' << 8) | ('c' << 16) | ('c' << 24) };
Samuel Huang06f1ae92018-03-13 18:19:34 +000039
40 uint32_t magic = 0;
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000041 uint16_t major_version = kInvalidVersion;
42 uint16_t minor_version = kInvalidVersion;
Samuel Huang06f1ae92018-03-13 18:19:34 +000043 uint32_t old_size = 0;
44 uint32_t old_crc = 0;
45 uint32_t new_size = 0;
46 uint32_t new_crc = 0;
47};
48
49// Sanity check.
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000050static_assert(sizeof(PatchHeader) == 24, "PatchHeader must be 24 bytes");
Samuel Huang06f1ae92018-03-13 18:19:34 +000051
52// Header for a patch element, found at the beginning of every patch element.
53struct PatchElementHeader {
54 uint32_t old_offset;
Samuel Huang06f1ae92018-03-13 18:19:34 +000055 uint32_t old_length;
Samuel Huangfd9b41c2018-05-04 16:11:56 +000056 uint32_t new_offset;
Samuel Huang06f1ae92018-03-13 18:19:34 +000057 uint32_t new_length;
Samuel Huangfd9b41c2018-05-04 16:11:56 +000058 uint32_t exe_type; // ExecutableType.
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000059 uint16_t version = kInvalidVersion;
Samuel Huang06f1ae92018-03-13 18:19:34 +000060};
61
62// Sanity check.
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000063static_assert(sizeof(PatchElementHeader) == 22,
64 "PatchElementHeader must be 22 bytes");
Samuel Huang06f1ae92018-03-13 18:19:34 +000065
66#pragma pack(pop)
67
68// Descibes a raw FIX operation.
69struct RawDeltaUnit {
70 offset_t copy_offset; // Offset in copy regions.
71 int8_t diff; // Bytewise difference.
72};
73
74// A Zucchini patch contains data streams encoded using varint format to reduce
75// uncompressed size.
76
77// Writes |value| as a varint in |dst| and returns an iterator pointing beyond
78// the written region. |dst| is assumed to hold enough space. Typically, this
79// will write to a vector using back insertion, e.g.:
80// EncodeVarUInt(value, std::back_inserter(vector));
81template <class T, class It>
82It EncodeVarUInt(T value, It dst) {
83 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
84
85 while (value >= 0x80) {
86 *dst++ = static_cast<uint8_t>(value) | 0x80;
87 value >>= 7;
88 }
89 *dst++ = static_cast<uint8_t>(value);
90 return dst;
91}
92
93// Same as EncodeVarUInt(), but for signed values.
94template <class T, class It>
95It EncodeVarInt(T value, It dst) {
96 static_assert(std::is_signed<T>::value, "Value type must be signed");
97
98 using unsigned_value_type = typename std::make_unsigned<T>::type;
99 if (value < 0)
100 return EncodeVarUInt((unsigned_value_type(~value) << 1) | 1, dst);
101 else
102 return EncodeVarUInt(unsigned_value_type(value) << 1, dst);
103}
104
105// Tries to read a varint unsigned integer from |[first, last)|. If
106// succesful, writes result into |value| and returns the number of bytes
107// read from |[first, last)|. Otherwise returns 0.
108template <class T, class It>
109typename std::iterator_traits<It>::difference_type DecodeVarUInt(It first,
110 It last,
111 T* value) {
112 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
113
114 uint8_t sh = 0;
115 T val = 0;
116 for (auto it = first; it != last;) {
117 val |= T(*it & 0x7F) << sh;
118 if (*(it++) < 0x80) {
119 *value = val;
120 return it - first;
121 }
122 sh += 7;
123 if (sh >= sizeof(T) * 8) // Overflow!
124 return 0;
125 }
126 return 0;
127}
128
129// Same as DecodeVarUInt(), but for signed values.
130template <class T, class It>
131typename std::iterator_traits<It>::difference_type DecodeVarInt(It first,
132 It last,
133 T* value) {
134 static_assert(std::is_signed<T>::value, "Value type must be signed");
135
136 typename std::make_unsigned<T>::type tmp = 0;
137 auto res = DecodeVarUInt(first, last, &tmp);
138 if (res) {
139 if (tmp & 1)
140 *value = ~static_cast<T>(tmp >> 1);
141 else
142 *value = static_cast<T>(tmp >> 1);
143 }
144 return res;
145}
146
147} // namespace zucchini
148
149#endif // COMPONENTS_ZUCCHINI_PATCH_UTILS_H_