xref: /aosp_15_r20/external/zucchini/patch_utils.h (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1 // 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 #include "components/zucchini/version_info.h"
15 
16 namespace zucchini {
17 
18 // 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.
26 struct PatchHeader {
27   // Magic signature at the beginning of a Zucchini patch file.
28   enum : uint32_t { kMagic = 'Z' | ('u' << 8) | ('c' << 16) | ('c' << 24) };
29 
30   uint32_t magic = 0;
31   uint16_t major_version = kInvalidVersion;
32   uint16_t minor_version = kInvalidVersion;
33   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.
40 static_assert(sizeof(PatchHeader) == 24, "PatchHeader must be 24 bytes");
41 
42 // Header for a patch element, found at the beginning of every patch element.
43 struct PatchElementHeader {
44   uint32_t old_offset;
45   uint32_t old_length;
46   uint32_t new_offset;
47   uint32_t new_length;
48   uint32_t exe_type;  // ExecutableType.
49   uint16_t version = kInvalidVersion;
50 };
51 
52 // Sanity check.
53 static_assert(sizeof(PatchElementHeader) == 22,
54               "PatchElementHeader must be 22 bytes");
55 
56 #pragma pack(pop)
57 
58 // Descibes a raw FIX operation.
59 struct 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));
71 template <class T, class It>
EncodeVarUInt(T value,It dst)72 It 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.
84 template <class T, class It>
EncodeVarInt(T value,It dst)85 It 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.
98 template <class T, class It>
DecodeVarUInt(It first,It last,T * value)99 typename 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.
120 template <class T, class It>
DecodeVarInt(It first,It last,T * value)121 typename 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_
140