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