Chromium Code Reviews| OLD | NEW |
|---|---|
| (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(¤t_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(¤t_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 | |
| OLD | NEW |