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