Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(711)

Side by Side Diff: components/safe_browsing_db/v4_rice.cc

Issue 2183433002: PVer4: RICE decode bytes to list of uint32 or 4-byte hash prefixes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add release mode only tests for cases that hit NOTREACHED Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 #include "base/logging.h"
6 #include "base/strings/stringprintf.h"
7 #include "components/safe_browsing_db/v4_rice.h"
8
9 using ::google::protobuf::RepeatedField;
10 using ::google::protobuf::int32;
11
12 namespace safe_browsing {
13
14 namespace {
15
16 const unsigned int kMaxBitIndex = 8 * sizeof(uint32_t);
17
18 void GetBytesFromUInt32(uint32_t word, char* bytes) {
19 const size_t mask = 0xFF;
20 bytes[0] = (char)(word & mask);
21 bytes[1] = (char)((word >> 8) & mask);
22 bytes[2] = (char)((word >> 16) & mask);
23 bytes[3] = (char)((word >> 24) & mask);
24 }
25
26 } // namespace
27
28 // static
29 V4DecodeResult V4RiceDecoder::ValidateInput(const int32 rice_parameter,
30 const int32 num_entries,
31 const std::string& encoded_data) {
32 if (num_entries < 0) {
33 NOTREACHED();
34 return NUM_ENTRIES_NEGATIVE_FAILURE;
35 }
36
37 if (num_entries == 0) {
38 return DECODE_SUCCESS;
39 }
40
41 if (rice_parameter <= 0) {
42 NOTREACHED();
43 return RICE_PARAMETER_NON_POSITIVE_FAILURE;
44 }
45
46 if (encoded_data.empty()) {
47 NOTREACHED();
48 return ENCODED_DATA_UNEXPECTED_EMPTY_FAILURE;
49 }
50
51 return DECODE_SUCCESS;
52 }
53
54 // static
55 V4DecodeResult V4RiceDecoder::DecodeIntegers(const int32 first_value,
56 const int32 rice_parameter,
57 const int32 num_entries,
58 const std::string& encoded_data,
59 RepeatedField<int32>* out) {
60 DCHECK(out);
61
62 V4DecodeResult result =
63 ValidateInput(rice_parameter, num_entries, encoded_data);
64 if (result != DECODE_SUCCESS) {
65 return result;
66 }
67
68 out->Reserve(num_entries + 1);
69 int32 last_value = first_value;
70 out->Add(last_value);
71 if (num_entries == 0) {
72 return DECODE_SUCCESS;
73 }
74
75 V4RiceDecoder decoder(rice_parameter, num_entries, encoded_data);
76 while (decoder.HasAnotherValue()) {
77 uint32_t offset;
78 result = decoder.GetNextValue(&offset);
79 if (result != DECODE_SUCCESS) {
80 return result;
81 }
82 DCHECK_LT(last_value, int32(last_value + offset));
83 last_value += offset;
84 out->Add(last_value);
85 }
86
87 return DECODE_SUCCESS;
88 }
89
90 // static
91 V4DecodeResult V4RiceDecoder::DecodeBytes(const int32 first_value,
92 const int32 rice_parameter,
93 const int32 num_entries,
94 const std::string& encoded_data,
95 std::string* out) {
96 DCHECK(out);
97
98 V4DecodeResult result =
99 ValidateInput(rice_parameter, num_entries, encoded_data);
100 if (result != DECODE_SUCCESS) {
101 return result;
102 }
103
104 out->reserve((num_entries + 1) * 4);
105 char bytes[4];
106 uint32_t last_value = first_value;
107 GetBytesFromUInt32(last_value, bytes);
108 out->append(bytes, 4);
109
110 if (num_entries == 0) {
111 return DECODE_SUCCESS;
112 }
113
114 V4RiceDecoder decoder(rice_parameter, num_entries, encoded_data);
115 while (decoder.HasAnotherValue()) {
116 uint32_t offset;
117 result = decoder.GetNextValue(&offset);
118 if (result != DECODE_SUCCESS) {
119 return result;
120 }
121 DCHECK_LT(last_value, last_value + offset);
palmer 2016/07/28 19:26:47 We need to make this a production sanity test, not
vakh (use Gerrit instead) 2016/07/28 19:57:21 I didn't know. Thanks for pointing it out. Also ad
122 last_value += offset;
123
124 GetBytesFromUInt32(last_value, bytes);
125 out->append(bytes, 4);
126 }
127
128 return DECODE_SUCCESS;
129 }
130
131 V4RiceDecoder::V4RiceDecoder(const int rice_parameter,
132 const int num_entries,
133 const std::string& encoded_data)
134 : rice_parameter_(rice_parameter),
135 num_entries_(num_entries),
136 data_(encoded_data),
137 current_word_(0) {
138 DCHECK_LE(0, num_entries_);
139 DCHECK_LE(2u, rice_parameter_);
140 DCHECK_GE(28u, rice_parameter_);
141
142 data_byte_index_ = 0;
143 current_word_bit_index_ = kMaxBitIndex;
144 }
145
146 V4RiceDecoder::~V4RiceDecoder() {}
147
148 bool V4RiceDecoder::HasAnotherValue() const {
149 return num_entries_ > 0;
150 }
151
152 V4DecodeResult V4RiceDecoder::GetNextValue(uint32_t* value) {
153 if (!HasAnotherValue()) {
154 return DECODE_NO_MORE_ENTRIES_FAILURE;
155 }
156
157 V4DecodeResult result;
158 uint32_t q = 0;
159 uint32_t bit;
160 do {
161 result = GetNextBits(1, &bit);
162 if (result != DECODE_SUCCESS) {
163 return result;
164 }
165 q += bit;
166 } while (bit);
167 uint32_t r = 0;
168 result = GetNextBits(rice_parameter_, &r);
169 if (result != DECODE_SUCCESS) {
170 return result;
171 }
172
173 *value = (q << rice_parameter_) + r;
174 num_entries_--;
175 return DECODE_SUCCESS;
176 }
177
178 V4DecodeResult V4RiceDecoder::GetNextWord(uint32_t* word) {
179 if (data_byte_index_ >= data_.size()) {
180 return DECODE_RAN_OUT_OF_BITS_FAILURE;
181 }
182
183 const size_t mask = 0xFF;
184 *word = (data_[data_byte_index_] & mask);
185 data_byte_index_++;
186 current_word_bit_index_ = 0;
187
188 if (data_byte_index_ < data_.size()) {
189 *word |= ((data_[data_byte_index_] & mask) << 8);
190 data_byte_index_++;
191
192 if (data_byte_index_ < data_.size()) {
193 *word |= ((data_[data_byte_index_] & mask) << 16);
194 data_byte_index_++;
195
196 if (data_byte_index_ < data_.size()) {
197 *word |= ((data_[data_byte_index_] & mask) << 24);
198 data_byte_index_++;
199 }
200 }
201 }
202
203 return DECODE_SUCCESS;
204 }
205
206 V4DecodeResult V4RiceDecoder::GetNextBits(unsigned int num_requested_bits,
207 uint32_t* x) {
208 if (num_requested_bits > kMaxBitIndex) {
209 NOTREACHED();
210 return DECODE_REQUESTED_TOO_MANY_BITS_FAILURE;
211 }
212
213 if (current_word_bit_index_ == kMaxBitIndex) {
214 V4DecodeResult result = GetNextWord(&current_word_);
215 if (result != DECODE_SUCCESS) {
216 return result;
217 }
218 }
219
220 unsigned int num_bits_left_in_current_word =
221 kMaxBitIndex - current_word_bit_index_;
222 if (num_bits_left_in_current_word >= num_requested_bits) {
223 // All the bits that we need are in |current_word_|.
224 GetBitsFromCurrentWord(num_requested_bits, x);
225 } else {
226 // |current_word_| contains fewer bits than we need so we store the current
227 // value of |current_word_| in |lower|, then read in a new |current_word_|,
228 // and then pick the remaining bits from the new value of |current_word_|.
229 uint32_t lower = current_word_;
230 // Bits we need after we read all of |current_word_|
231 unsigned int num_bits_from_next_word =
232 num_requested_bits - num_bits_left_in_current_word;
233 uint32_t upper;
234 V4DecodeResult result = GetNextWord(&current_word_);
235 if (result != DECODE_SUCCESS) {
236 return result;
237 }
238 GetBitsFromCurrentWord(num_bits_from_next_word, &upper);
239 *x = (upper << (num_requested_bits - num_bits_from_next_word)) | lower;
240 }
241 return DECODE_SUCCESS;
242 }
243
244 void V4RiceDecoder::GetBitsFromCurrentWord(unsigned int num_requested_bits,
245 uint32_t* x) {
246 uint32_t mask = 0xFFFFFFFF >> (kMaxBitIndex - num_requested_bits);
247 *x = current_word_ & mask;
248 current_word_ = current_word_ >> num_requested_bits;
249 current_word_bit_index_ += num_requested_bits;
250 };
251
252 std::string V4RiceDecoder::DebugString() const {
253 return base::StringPrintf(
254 "current_word_: %x; data_byte_index_; %x, "
255 "current_word_bit_index_: %x; rice_parameter_: %x",
256 current_word_, data_byte_index_, current_word_bit_index_,
257 rice_parameter_);
258 }
259
260 std::ostream& operator<<(std::ostream& os, const V4RiceDecoder& rice_decoder) {
261 os << rice_decoder.DebugString();
262 return os;
263 }
264
265 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698