blob: 82b2b485fa6fd65342da939fff695faf8d080bea [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"
Samuel Huang9a6bb562021-11-17 16:20:51 +000014#include "components/zucchini/version_info.h"
Samuel Huang06f1ae92018-03-13 18:19:34 +000015
16namespace zucchini {
17
Samuel Huang06f1ae92018-03-13 18:19:34 +000018// A Zucchini 'ensemble' patch is the concatenation of a patch header with a
19// list of patch 'elements', each containing data for patching individual
20// elements.
21
22// Supported by MSVC, g++, and clang++. Ensures no gaps in packing.
23#pragma pack(push, 1)
24
25// Header for a Zucchini patch, found at the beginning of an ensemble patch.
26struct PatchHeader {
27 // Magic signature at the beginning of a Zucchini patch file.
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000028 enum : uint32_t { kMagic = 'Z' | ('u' << 8) | ('c' << 16) | ('c' << 24) };
Samuel Huang06f1ae92018-03-13 18:19:34 +000029
30 uint32_t magic = 0;
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000031 uint16_t major_version = kInvalidVersion;
32 uint16_t minor_version = kInvalidVersion;
Samuel Huang06f1ae92018-03-13 18:19:34 +000033 uint32_t old_size = 0;
34 uint32_t old_crc = 0;
35 uint32_t new_size = 0;
36 uint32_t new_crc = 0;
37};
38
39// Sanity check.
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000040static_assert(sizeof(PatchHeader) == 24, "PatchHeader must be 24 bytes");
Samuel Huang06f1ae92018-03-13 18:19:34 +000041
42// Header for a patch element, found at the beginning of every patch element.
43struct PatchElementHeader {
44 uint32_t old_offset;
Samuel Huang06f1ae92018-03-13 18:19:34 +000045 uint32_t old_length;
Samuel Huangfd9b41c2018-05-04 16:11:56 +000046 uint32_t new_offset;
Samuel Huang06f1ae92018-03-13 18:19:34 +000047 uint32_t new_length;
Samuel Huangfd9b41c2018-05-04 16:11:56 +000048 uint32_t exe_type; // ExecutableType.
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000049 uint16_t version = kInvalidVersion;
Samuel Huang06f1ae92018-03-13 18:19:34 +000050};
51
52// Sanity check.
Etienne Pierre-dorayb90a9472021-10-28 21:16:04 +000053static_assert(sizeof(PatchElementHeader) == 22,
54 "PatchElementHeader must be 22 bytes");
Samuel Huang06f1ae92018-03-13 18:19:34 +000055
56#pragma pack(pop)
57
58// Descibes a raw FIX operation.
59struct RawDeltaUnit {
60 offset_t copy_offset; // Offset in copy regions.
61 int8_t diff; // Bytewise difference.
62};
63
64// A Zucchini patch contains data streams encoded using varint format to reduce
65// uncompressed size.
66
67// Writes |value| as a varint in |dst| and returns an iterator pointing beyond
68// the written region. |dst| is assumed to hold enough space. Typically, this
69// will write to a vector using back insertion, e.g.:
70// EncodeVarUInt(value, std::back_inserter(vector));
71template <class T, class It>
72It EncodeVarUInt(T value, It dst) {
73 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
74
75 while (value >= 0x80) {
76 *dst++ = static_cast<uint8_t>(value) | 0x80;
77 value >>= 7;
78 }
79 *dst++ = static_cast<uint8_t>(value);
80 return dst;
81}
82
83// Same as EncodeVarUInt(), but for signed values.
84template <class T, class It>
85It EncodeVarInt(T value, It dst) {
86 static_assert(std::is_signed<T>::value, "Value type must be signed");
87
88 using unsigned_value_type = typename std::make_unsigned<T>::type;
89 if (value < 0)
90 return EncodeVarUInt((unsigned_value_type(~value) << 1) | 1, dst);
91 else
92 return EncodeVarUInt(unsigned_value_type(value) << 1, dst);
93}
94
95// Tries to read a varint unsigned integer from |[first, last)|. If
96// succesful, writes result into |value| and returns the number of bytes
97// read from |[first, last)|. Otherwise returns 0.
98template <class T, class It>
99typename std::iterator_traits<It>::difference_type DecodeVarUInt(It first,
100 It last,
101 T* value) {
102 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned");
103
104 uint8_t sh = 0;
105 T val = 0;
106 for (auto it = first; it != last;) {
107 val |= T(*it & 0x7F) << sh;
108 if (*(it++) < 0x80) {
109 *value = val;
110 return it - first;
111 }
112 sh += 7;
113 if (sh >= sizeof(T) * 8) // Overflow!
114 return 0;
115 }
116 return 0;
117}
118
119// Same as DecodeVarUInt(), but for signed values.
120template <class T, class It>
121typename std::iterator_traits<It>::difference_type DecodeVarInt(It first,
122 It last,
123 T* value) {
124 static_assert(std::is_signed<T>::value, "Value type must be signed");
125
126 typename std::make_unsigned<T>::type tmp = 0;
127 auto res = DecodeVarUInt(first, last, &tmp);
128 if (res) {
129 if (tmp & 1)
130 *value = ~static_cast<T>(tmp >> 1);
131 else
132 *value = static_cast<T>(tmp >> 1);
133 }
134 return res;
135}
136
137} // namespace zucchini
138
139#endif // COMPONENTS_ZUCCHINI_PATCH_UTILS_H_