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

Side by Side Diff: third_party/hunspell/google/bdict_reader.cc

Issue 326013: Fixes for multiple potential out-of-bounds reads in hunspell::NodeReader.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Fixes for multiple potential out-of-bounds reads in hunspell::NodeReader. ... Created 11 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2008 Google Inc. All Rights Reserved. 1 // Copyright 2008 Google Inc. All Rights Reserved.
2 2
3 #include "third_party/hunspell/google/bdict_reader.h" 3 #include "third_party/hunspell/google/bdict_reader.h"
4 4
5 #include "base/logging.h" 5 #include "base/logging.h"
6 6
7 namespace hunspell { 7 namespace hunspell {
8 8
9 // Like the "Visitor" design pattern, this lightweight object provides an 9 // Like the "Visitor" design pattern, this lightweight object provides an
10 // interface around a serialized trie node at the given address in the memory. 10 // interface around a serialized trie node at the given address in the memory.
(...skipping 11 matching lines...) Expand all
22 // iterating. This happens when there is a lookup node with empty entries. 22 // iterating. This happens when there is a lookup node with empty entries.
23 FIND_NOTHING 23 FIND_NOTHING
24 }; 24 };
25 25
26 // The default constructor makes an invalid reader. 26 // The default constructor makes an invalid reader.
27 NodeReader(); 27 NodeReader();
28 NodeReader(const unsigned char* bdict_data, size_t bdict_length, 28 NodeReader(const unsigned char* bdict_data, size_t bdict_length,
29 size_t node_offset, int node_depth); 29 size_t node_offset, int node_depth);
30 30
31 // Returns true if the reader is valid. False means you shouldn't use it. 31 // Returns true if the reader is valid. False means you shouldn't use it.
32 bool is_valid() const { return !!bdict_data_; } 32 bool is_valid() const { return is_valid_; }
33 33
34 // Recursively finds the given NULL terminated word. 34 // Recursively finds the given NULL terminated word.
35 // See BDictReader::FindWord. 35 // See BDictReader::FindWord.
36 int FindWord(const unsigned char* word, 36 int FindWord(const unsigned char* word,
37 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const; 37 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const;
38 38
39 // Allows iterating over the children of this node. When it returns 39 // Allows iterating over the children of this node. When it returns
40 // FIND_NODE, |*result| will be populated with the reader for the found node. 40 // FIND_NODE, |*result| will be populated with the reader for the found node.
41 // The first index is 0. The single character for this node will be placed 41 // The first index is 0. The single character for this node will be placed
42 // into |*found_char|. 42 // into |*found_char|.
43 FindResult GetChildAt(int index, char* found_char, NodeReader* result) const; 43 FindResult GetChildAt(int index, char* found_char, NodeReader* result) const;
44 44
45 // Leaf ---------------------------------------------------------------------- 45 // Leaf ----------------------------------------------------------------------
46 46
47 inline bool is_leaf() const { 47 inline bool is_leaf() const {
48 // If id_byte() sets is_valid_ to false, we need an extra check to avoid
49 // returning true for this type.
48 return (id_byte() & BDict::LEAF_NODE_TYPE_MASK) == 50 return (id_byte() & BDict::LEAF_NODE_TYPE_MASK) ==
49 BDict::LEAF_NODE_TYPE_VALUE; 51 BDict::LEAF_NODE_TYPE_VALUE && is_valid_;
jschuh 2012/07/20 23:16:16 Since id_byte() does an is_valid_ check this is re
50 } 52 }
51 53
52 // If this is a leaf node with an additional string, this function will return 54 // If this is a leaf node with an additional string, this function will return
53 // a pointer to the beginning of the additional string. It will be NULL 55 // a pointer to the beginning of the additional string. It will be NULL
54 // terminated. If it is not a leaf or has no additional string, it will return 56 // terminated. If it is not a leaf or has no additional string, it will return
55 // NULL. 57 // NULL.
56 inline const unsigned char* additional_string_for_leaf() const { 58 inline const unsigned char* additional_string_for_leaf() const {
57 // Leaf nodes with additional strings start with bits "01" in the ID byte. 59 // Leaf nodes with additional strings start with bits "01" in the ID byte.
58 if ((id_byte() & BDict::LEAF_NODE_ADDITIONAL_MASK) == 60 if ((id_byte() & BDict::LEAF_NODE_ADDITIONAL_MASK) ==
59 BDict::LEAF_NODE_ADDITIONAL_VALUE) 61 BDict::LEAF_NODE_ADDITIONAL_VALUE) {
60 return &bdict_data_[node_offset_ + 2]; // Starts after the 2 byte ID. 62 if (node_offset_ < (bdict_length_ - 2))
63 return &bdict_data_[node_offset_ + 2]; // Starts after the 2 byte ID.
64 // Otherwise the dictionary is corrupt.
65 is_valid_ = false;
66 }
61 return NULL; 67 return NULL;
62 } 68 }
63 69
64 // Returns the first affix ID corresponding to the given leaf node. The 70 // Returns the first affix ID corresponding to the given leaf node. The
65 // current node must be a leaf or this will do the wrong thing. There may be 71 // current node must be a leaf or this will do the wrong thing. There may be
66 // additional affix IDs following the node when leaf_has_following is set, 72 // additional affix IDs following the node when leaf_has_following is set,
67 // but this will not handle those. 73 // but this will not handle those.
68 inline int affix_id_for_leaf() const { 74 inline int affix_id_for_leaf() const {
75 if (node_offset_ >= bdict_length_ - 2) {
76 is_valid_ = false;
77 return 0;
78 }
69 // Take the lowest 6 bits of the first byte, and all 8 bits of the second. 79 // Take the lowest 6 bits of the first byte, and all 8 bits of the second.
70 return ((bdict_data_[node_offset_ + 0] & 80 return ((bdict_data_[node_offset_ + 0] &
71 BDict::LEAF_NODE_FIRST_BYTE_AFFIX_MASK) << 8) + 81 BDict::LEAF_NODE_FIRST_BYTE_AFFIX_MASK) << 8) +
72 bdict_data_[node_offset_ + 1]; 82 bdict_data_[node_offset_ + 1];
73 } 83 }
74 84
75 // Returns true if there is a list of additional affix matches following this 85 // Returns true if there is a list of additional affix matches following this
76 // leaf node. 86 // leaf node.
77 inline bool leaf_has_following() const { 87 inline bool leaf_has_following() const {
78 return ((id_byte() & BDict::LEAF_NODE_FOLLOWING_MASK) == 88 return ((id_byte() & BDict::LEAF_NODE_FOLLOWING_MASK) ==
(...skipping 20 matching lines...) Expand all
99 BDict::LOOKUP_NODE_32BIT_VALUE; 109 BDict::LOOKUP_NODE_32BIT_VALUE;
100 } 110 }
101 111
102 inline bool lookup_has_0th() const { 112 inline bool lookup_has_0th() const {
103 return (id_byte() & BDict::LOOKUP_NODE_0TH_MASK) == 113 return (id_byte() & BDict::LOOKUP_NODE_0TH_MASK) ==
104 BDict::LOOKUP_NODE_0TH_VALUE; 114 BDict::LOOKUP_NODE_0TH_VALUE;
105 } 115 }
106 116
107 // Returns the first entry after the lookup table header. When there is a 117 // Returns the first entry after the lookup table header. When there is a
108 // magic 0th entry, it will be that address. 118 // magic 0th entry, it will be that address.
119 // The caller checks that the result is in-bounds.
109 inline size_t zeroth_entry_offset() const { 120 inline size_t zeroth_entry_offset() const {
110 return node_offset_ + 3; 121 return node_offset_ + 3;
111 } 122 }
112 123
113 // Returns the index of the first element in the lookup table. This skips any 124 // Returns the index of the first element in the lookup table. This skips any
114 // magic 0th entry. 125 // magic 0th entry.
126 // The caller checks that the result is in-bounds.
115 size_t lookup_table_offset() const { 127 size_t lookup_table_offset() const {
116 size_t table_offset = zeroth_entry_offset(); 128 size_t table_offset = zeroth_entry_offset();
117 if (lookup_has_0th()) 129 if (lookup_has_0th())
118 return table_offset + (is_lookup_32() ? 4 : 2); 130 return table_offset + (is_lookup_32() ? 4 : 2);
119 return table_offset; 131 return table_offset;
120 } 132 }
121 133
122 inline unsigned char lookup_first_char() const { 134 inline int lookup_first_char() const {
135 if (node_offset_ >= bdict_length_ - 1) {
136 is_valid_ = false;
137 return 0;
138 }
123 return bdict_data_[node_offset_ + 1]; 139 return bdict_data_[node_offset_ + 1];
124 } 140 }
125 141
126 inline int lookup_num_chars() const { 142 inline int lookup_num_chars() const {
143 if (node_offset_ >= bdict_length_ - 2) {
144 is_valid_ = false;
145 return 0;
146 }
127 return bdict_data_[node_offset_ + 2]; 147 return bdict_data_[node_offset_ + 2];
128 } 148 }
129 149
130 // Computes a node reader for the magic 0th entry of the table. This assumes 150 // Computes a node reader for the magic 0th entry of the table. This assumes
131 // it has a 0th entry. This will always return FOUND_NODE (for compatilibility 151 // it has a 0th entry. This will always return FOUND_NODE (for compatilibility
132 // with GetChildAt). 152 // with GetChildAt).
133 FindResult ReaderForLookup0th(NodeReader* result) const; 153 FindResult ReaderForLookup0th(NodeReader* result) const;
134 154
135 // Gets a node reader for the |offset|th element in the table, not counting 155 // Gets a node reader for the |offset|th element in the table, not counting
136 // the magic 0th element, if any (so passing 0 here will give you the first 156 // the magic 0th element, if any (so passing 0 here will give you the first
(...skipping 23 matching lines...) Expand all
160 return id_byte() & BDict::LIST_NODE_COUNT_MASK; 180 return id_byte() & BDict::LIST_NODE_COUNT_MASK;
161 } 181 }
162 182
163 // Returns a NodeReader for the list item with the given index. The single 183 // Returns a NodeReader for the list item with the given index. The single
164 // character for this node will be placed into |*found_char|. 184 // character for this node will be placed into |*found_char|.
165 FindResult ReaderForListAt(size_t index, char* found_char, 185 FindResult ReaderForListAt(size_t index, char* found_char,
166 NodeReader* result) const; 186 NodeReader* result) const;
167 187
168 private: 188 private:
169 inline unsigned char id_byte() const { 189 inline unsigned char id_byte() const {
170 DCHECK(node_offset_ < bdict_length_); 190 if (!is_valid_)
191 return 0; // Don't continue with a corrupt node.
192 if (node_offset_ >= bdict_length_) {
193 // Return zero if out of bounds; we'll check is_valid_ in caller.
194 is_valid_ = false;
195 return 0;
196 }
171 return bdict_data_[node_offset_]; 197 return bdict_data_[node_offset_];
172 } 198 }
173 199
174 // Checks the given leaf node to see if it's a match for the given word. 200 // Checks the given leaf node to see if it's a match for the given word.
175 // The parameters and return values are the same as BDictReader::FindWord. 201 // The parameters and return values are the same as BDictReader::FindWord.
176 int CompareLeafNode(const unsigned char* word, 202 int CompareLeafNode(const unsigned char* word,
177 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const; 203 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const;
178 204
179 // Recursive calls used by FindWord to look up child nodes of different types. 205 // Recursive calls used by FindWord to look up child nodes of different types.
180 int FindInLookup(const unsigned char* word, 206 int FindInLookup(const unsigned char* word,
181 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const; 207 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const;
182 int FindInList(const unsigned char* word, 208 int FindInList(const unsigned char* word,
183 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const; 209 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const;
184 210
185 // The entire bdict file. This will be NULL if it is invalid. 211 // The entire bdict file. This will be NULL if it is invalid.
186 const unsigned char* bdict_data_; 212 const unsigned char* bdict_data_;
187 size_t bdict_length_; 213 size_t bdict_length_;
214 // Points to the end of the file (for length checking convenience).
215 const unsigned char* bdict_end_;
188 216
189 // Absolute offset within |bdict_data_| of the beginning of this node. 217 // Absolute offset within |bdict_data_| of the beginning of this node.
190 size_t node_offset_; 218 size_t node_offset_;
191 219
192 // The character index into the word that this node represents. 220 // The character index into the word that this node represents.
193 int node_depth_; 221 int node_depth_;
222
223 // Signals that dictionary corruption was found during node traversal.
224 mutable bool is_valid_;
194 }; 225 };
195 226
196 NodeReader::NodeReader() 227 NodeReader::NodeReader()
197 : bdict_data_(NULL), 228 : bdict_data_(NULL),
198 bdict_length_(0), 229 bdict_length_(0),
230 bdict_end_(NULL),
199 node_offset_(0), 231 node_offset_(0),
200 node_depth_(0) { 232 node_depth_(0),
233 is_valid_(false) {
201 } 234 }
202 235
203 NodeReader::NodeReader(const unsigned char* bdict_data, size_t bdict_length, 236 NodeReader::NodeReader(const unsigned char* bdict_data, size_t bdict_length,
204 size_t node_offset, int node_depth) 237 size_t node_offset, int node_depth)
205 : bdict_data_(bdict_data), 238 : bdict_data_(bdict_data),
206 bdict_length_(bdict_length), 239 bdict_length_(bdict_length),
240 bdict_end_(bdict_data + bdict_length),
207 node_offset_(node_offset), 241 node_offset_(node_offset),
208 node_depth_(node_depth) { 242 node_depth_(node_depth),
243 is_valid_(bdict_data != NULL && node_offset < bdict_length) {
209 } 244 }
210 245
211 int NodeReader::FindWord(const unsigned char* word, 246 int NodeReader::FindWord(const unsigned char* word,
212 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const { 247 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const {
213 if (is_leaf()) 248 if (is_leaf())
214 return CompareLeafNode(word, affix_indices); 249 return CompareLeafNode(word, affix_indices);
215 250
216 if (is_lookup()) 251 if (is_lookup())
217 return FindInLookup(word, affix_indices); 252 return FindInLookup(word, affix_indices);
218 if (is_list()) 253 if (is_list())
(...skipping 27 matching lines...) Expand all
246 if (!additional) { 281 if (!additional) {
247 // No additional string. This means we should have reached the end of the 282 // No additional string. This means we should have reached the end of the
248 // word to get a match. 283 // word to get a match.
249 if (word[node_depth_] != 0) 284 if (word[node_depth_] != 0)
250 return 0; 285 return 0;
251 return FillAffixesForLeafMatch(0, affix_indices); 286 return FillAffixesForLeafMatch(0, affix_indices);
252 } 287 }
253 288
254 // Check the additional string. 289 // Check the additional string.
255 int cur = 0; 290 int cur = 0;
256 while (additional[cur]) { 291 while (&additional[cur] < bdict_end_ && additional[cur]) {
257 if (word[node_depth_ + cur] != additional[cur]) 292 if (word[node_depth_ + cur] != additional[cur])
258 return 0; // Not a match. 293 return 0; // Not a match.
259 cur++; 294 cur++;
260 } 295 }
261 296
297 if (&additional[cur] == bdict_end_) {
298 is_valid_ = false;
299 return 0;
300 }
301
262 // Got to the end of the additional string, the word should also be over for 302 // Got to the end of the additional string, the word should also be over for
263 // a match (the same as above). 303 // a match (the same as above).
264 if (word[node_depth_ + cur] != 0) 304 if (word[node_depth_ + cur] != 0)
265 return 0; 305 return 0;
266 return FillAffixesForLeafMatch(cur + 1, affix_indices); 306 return FillAffixesForLeafMatch(cur + 1, affix_indices);
267 } 307 }
268 308
269 int NodeReader::FillAffixesForLeafMatch( 309 int NodeReader::FillAffixesForLeafMatch(
270 size_t additional_bytes, 310 size_t additional_bytes,
271 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const { 311 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const {
272 // The first match is easy, it always comes from the affix_id included in the 312 // The first match is easy, it always comes from the affix_id included in the
273 // leaf node. 313 // leaf node.
274 affix_indices[0] = affix_id_for_leaf(); 314 affix_indices[0] = affix_id_for_leaf();
275 315
276 if (!leaf_has_following() && affix_indices[0] != BDict::FIRST_AFFIX_IS_UNUSED) 316 if (!leaf_has_following() && affix_indices[0] != BDict::FIRST_AFFIX_IS_UNUSED)
277 return 1; // Common case: no additional affix group IDs. 317 return 1; // Common case: no additional affix group IDs.
278 318
279 // We may or may not need to ignore that first value we just read, since it 319 // We may or may not need to ignore that first value we just read, since it
280 // could be a dummy placeholder value. The |list_offset| is the starting 320 // could be a dummy placeholder value. The |list_offset| is the starting
281 // position in the output list to write the rest of the values, which may 321 // position in the output list to write the rest of the values, which may
282 // overwrite the first value. 322 // overwrite the first value.
283 int list_offset = 1; 323 int list_offset = 1;
284 if (affix_indices[0] == BDict::FIRST_AFFIX_IS_UNUSED) 324 if (affix_indices[0] == BDict::FIRST_AFFIX_IS_UNUSED)
285 list_offset = 0; 325 list_offset = 0;
286 326
327 // Save the end pointer (accounting for an odd number of bytes).
328 size_t array_start = node_offset_ + additional_bytes + 2;
329 const uint16* const bdict_short_end = reinterpret_cast<const uint16*>(
330 &bdict_data_[((bdict_length_ - array_start) & -2) + array_start]);
287 // Process all remaining matches. 331 // Process all remaining matches.
288 const unsigned short* following_array = 332 const uint16* following_array = reinterpret_cast<const uint16*>(
289 reinterpret_cast<const unsigned short*>( 333 &bdict_data_[array_start]);
290 &bdict_data_[node_offset_ + additional_bytes + 2]);
291 for (int i = 0; i < BDict::MAX_AFFIXES_PER_WORD - list_offset; i++) { 334 for (int i = 0; i < BDict::MAX_AFFIXES_PER_WORD - list_offset; i++) {
335 if (&following_array[i] >= bdict_short_end) {
336 is_valid_ = false;
337 return 0;
338 }
292 if (following_array[i] == BDict::LEAF_NODE_FOLLOWING_LIST_TERMINATOR) 339 if (following_array[i] == BDict::LEAF_NODE_FOLLOWING_LIST_TERMINATOR)
293 return i + list_offset; // Found the end of the list. 340 return i + list_offset; // Found the end of the list.
294 affix_indices[i + list_offset] = following_array[i]; 341 affix_indices[i + list_offset] = following_array[i];
295 } 342 }
296 return BDict::MAX_AFFIXES_PER_WORD; 343 return BDict::MAX_AFFIXES_PER_WORD;
297 } 344 }
298 345
299 int NodeReader::FindInLookup( 346 int NodeReader::FindInLookup(
300 const unsigned char* word, 347 const unsigned char* word,
301 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const { 348 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const {
(...skipping 30 matching lines...) Expand all
332 child_offset = *reinterpret_cast<const unsigned int*>( 379 child_offset = *reinterpret_cast<const unsigned int*>(
333 &bdict_data_[zeroth_entry_offset()]); 380 &bdict_data_[zeroth_entry_offset()]);
334 } else { 381 } else {
335 child_offset = *reinterpret_cast<const unsigned short*>( 382 child_offset = *reinterpret_cast<const unsigned short*>(
336 &bdict_data_[zeroth_entry_offset()]); 383 &bdict_data_[zeroth_entry_offset()]);
337 child_offset += node_offset_; 384 child_offset += node_offset_;
338 } 385 }
339 386
340 // Range check the offset; 387 // Range check the offset;
341 if (child_offset >= bdict_length_) { 388 if (child_offset >= bdict_length_) {
342 DCHECK(false) << "Offset should be less than length."; 389 is_valid_ = false;
343 return FIND_DONE; 390 return FIND_DONE;
344 } 391 }
345 392
346 // Now recurse into that child node. We don't advance to the next character 393 // Now recurse into that child node. We don't advance to the next character
347 // here since the 0th element will be a leaf (see ReaderForLookupAt). 394 // here since the 0th element will be a leaf (see ReaderForLookupAt).
348 *result = NodeReader(bdict_data_, bdict_length_, child_offset, node_depth_); 395 *result = NodeReader(bdict_data_, bdict_length_, child_offset, node_depth_);
349 return FIND_NODE; 396 return FIND_NODE;
350 } 397 }
351 398
352 NodeReader::FindResult NodeReader::ReaderForLookupAt( 399 NodeReader::FindResult NodeReader::ReaderForLookupAt(
353 size_t index, 400 size_t index,
354 char* found_char, 401 char* found_char,
355 NodeReader* result) const { 402 NodeReader* result) const {
356 const unsigned char* table_begin = &bdict_data_[lookup_table_offset()]; 403 const unsigned char* table_begin = &bdict_data_[lookup_table_offset()];
357 404
358 if (index >= static_cast<size_t>(lookup_num_chars())) 405 if (index >= static_cast<size_t>(lookup_num_chars()) || !is_valid_)
359 return FIND_DONE; 406 return FIND_DONE;
360 407
361 size_t child_offset; 408 size_t child_offset;
362 if (is_lookup_32()) { 409 if (is_lookup_32()) {
363 // Table contains 32-bit absolute offsets. 410 // Table contains 32-bit absolute offsets.
364 child_offset = 411 child_offset =
365 reinterpret_cast<const unsigned int*>(table_begin)[index]; 412 reinterpret_cast<const unsigned int*>(table_begin)[index];
366 if (!child_offset) 413 if (!child_offset)
367 return FIND_NOTHING; // This entry in the table is empty. 414 return FIND_NOTHING; // This entry in the table is empty.
368 } else { 415 } else {
369 // Table contains 16-bit offsets relative to the current node. 416 // Table contains 16-bit offsets relative to the current node.
370 child_offset = 417 child_offset =
371 reinterpret_cast<const unsigned short*>(table_begin)[index]; 418 reinterpret_cast<const unsigned short*>(table_begin)[index];
372 if (!child_offset) 419 if (!child_offset)
373 return FIND_NOTHING; // This entry in the table is empty. 420 return FIND_NOTHING; // This entry in the table is empty.
374 child_offset += node_offset_; 421 child_offset += node_offset_;
375 } 422 }
376 423
377 // Range check the offset; 424 // Range check the offset;
378 if (child_offset >= bdict_length_) { 425 if (child_offset >= bdict_length_) {
379 DCHECK(false) << "Offset should be less than length."; 426 is_valid_ = false;
380 return FIND_DONE; // Error. 427 return FIND_DONE; // Error.
381 } 428 }
382 429
383 // This is a bit tricky. When we've just reached the end of a word, the word 430 // This is a bit tricky. When we've just reached the end of a word, the word
384 // itself will be stored in a leaf "node" off of this node. That node, of 431 // itself will be stored in a leaf "node" off of this node. That node, of
385 // course, will want to know that it's the end of the word and so we have to 432 // course, will want to know that it's the end of the word and so we have to
386 // have it use the same index into the word as we're using at this level. 433 // have it use the same index into the word as we're using at this level.
387 // 434 //
388 // This happens when there is a word in the dictionary that is a strict 435 // This happens when there is a word in the dictionary that is a strict
389 // prefix of other words in the dictionary, and so we'll have a non-leaf 436 // prefix of other words in the dictionary, and so we'll have a non-leaf
390 // node representing the entire word before the ending leaf node. 437 // node representing the entire word before the ending leaf node.
391 // 438 //
392 // In all other cases, we want to advance to the next character. Even if the 439 // In all other cases, we want to advance to the next character. Even if the
393 // child node is a leaf, it will have an additional character that it will 440 // child node is a leaf, it will have an additional character that it will
394 // want to check. 441 // want to check.
395 *found_char = static_cast<char>(index + lookup_first_char()); 442 *found_char = static_cast<char>(index + lookup_first_char());
443 if (!is_valid_)
444 return FIND_DONE;
396 int char_advance = *found_char == 0 ? 0 : 1; 445 int char_advance = *found_char == 0 ? 0 : 1;
397 446
398 *result = NodeReader(bdict_data_, bdict_length_, 447 *result = NodeReader(bdict_data_, bdict_length_,
399 child_offset, node_depth_ + char_advance); 448 child_offset, node_depth_ + char_advance);
400 return FIND_NODE; 449 return FIND_NODE;
401 } 450 }
402 451
403 int NodeReader::FindInList( 452 int NodeReader::FindInList(
404 const unsigned char* word, 453 const unsigned char* word,
405 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const { 454 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const {
406 unsigned char next_char = word[node_depth_]; 455 unsigned char next_char = word[node_depth_];
407 456
408 // TODO(brettw) replace with binary search. 457 // TODO(brettw) replace with binary search.
409 size_t list_count = list_item_count(); 458 size_t list_count = list_item_count();
410 const unsigned char* list_begin = &bdict_data_[node_offset_ + 1]; 459 const unsigned char* list_begin = &bdict_data_[node_offset_ + 1];
411 460
412 int bytes_per_index = (is_list_16() ? 3 : 2); 461 int bytes_per_index = (is_list_16() ? 3 : 2);
413 462
414 for (size_t i = 0; i < list_count; i++) { 463 for (size_t i = 0; i < list_count; i++) {
415 if (list_begin[i * bytes_per_index] == next_char) { 464 const unsigned char* list_current = &list_begin[i * bytes_per_index];
465 if (list_current >= bdict_end_) {
466 is_valid_ = false;
467 return 0;
468 }
469 if (*list_current == next_char) {
416 // Found a match. 470 // Found a match.
417 char dummy_char; 471 char dummy_char;
418 NodeReader child_reader; 472 NodeReader child_reader;
419 if (ReaderForListAt(i, &dummy_char, &child_reader) != FIND_NODE) 473 if (ReaderForListAt(i, &dummy_char, &child_reader) != FIND_NODE)
420 return 0; 474 return 0;
421 DCHECK(dummy_char == static_cast<char>(next_char)); 475 DCHECK(dummy_char == static_cast<char>(next_char));
422 return child_reader.FindWord(word, affix_indices); 476 return child_reader.FindWord(word, affix_indices);
423 } 477 }
424 } 478 }
425 return 0; 479 return 0;
(...skipping 19 matching lines...) Expand all
445 &list_item_begin[1]); 499 &list_item_begin[1]);
446 } else { 500 } else {
447 const unsigned char* list_item_begin = bdict_data_ + list_begin + index * 2; 501 const unsigned char* list_item_begin = bdict_data_ + list_begin + index * 2;
448 *found_char = list_item_begin[0]; 502 *found_char = list_item_begin[0];
449 503
450 size_t children_begin = list_begin + list_item_count() * 2; 504 size_t children_begin = list_begin + list_item_count() * 2;
451 offset = children_begin + list_item_begin[1]; 505 offset = children_begin + list_item_begin[1];
452 } 506 }
453 507
454 if (offset == 0 || node_offset_ >= bdict_length_) { 508 if (offset == 0 || node_offset_ >= bdict_length_) {
455 DCHECK(false) << "Offset should be less than length."; 509 is_valid_ = false;
456 return FIND_DONE; // Error, should not happen except for corruption. 510 return FIND_DONE; // Error, should not happen except for corruption.
457 } 511 }
458 512
459 int char_advance = *found_char == 0 ? 0 : 1; // See ReaderForLookupAt. 513 int char_advance = *found_char == 0 ? 0 : 1; // See ReaderForLookupAt.
460 *result = NodeReader(bdict_data_, bdict_length_, 514 *result = NodeReader(bdict_data_, bdict_length_,
461 offset, node_depth_ + char_advance); 515 offset, node_depth_ + char_advance);
462 return FIND_NODE; 516 return FIND_NODE;
463 } 517 }
464 518
465 // WordIterator ---------------------------------------------------------------- 519 // WordIterator ----------------------------------------------------------------
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 header_->dic_offset > bdict_length) 710 header_->dic_offset > bdict_length)
657 return false; 711 return false;
658 712
659 // Get the affix header, make sure there is enough room for it. 713 // Get the affix header, make sure there is enough room for it.
660 if (header_->aff_offset + sizeof(BDict::AffHeader) > bdict_length) 714 if (header_->aff_offset + sizeof(BDict::AffHeader) > bdict_length)
661 return false; 715 return false;
662 aff_header_ = reinterpret_cast<const BDict::AffHeader*>( 716 aff_header_ = reinterpret_cast<const BDict::AffHeader*>(
663 &bdict_data[header_->aff_offset]); 717 &bdict_data[header_->aff_offset]);
664 718
665 // Make sure there is enough room for the affix group count dword. 719 // Make sure there is enough room for the affix group count dword.
666 if (aff_header_->affix_group_offset + sizeof(uint32) > bdict_length) 720 if (aff_header_->affix_group_offset > bdict_length - sizeof(uint32))
667 return false; 721 return false;
668 722
669 // Don't set these until the end. This way, NULL bdict_data_ will indicate 723 // Don't set these until the end. This way, NULL bdict_data_ will indicate
670 // failure. 724 // failure.
671 bdict_data_ = bdict_data; 725 bdict_data_ = bdict_data;
672 bdict_length_ = bdict_length; 726 bdict_length_ = bdict_length;
673 return true; 727 return true;
674 } 728 }
675 729
676 int BDictReader::FindWord( 730 int BDictReader::FindWord(
677 const char* word, 731 const char* word,
678 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const { 732 int affix_indices[BDict::MAX_AFFIXES_PER_WORD]) const {
679 if (!bdict_data_ || 733 if (!bdict_data_ ||
680 header_->dic_offset > bdict_length_) { 734 header_->dic_offset >= bdict_length_) {
681 // When the dictionary is corrupt, we return 0 which means the word is valid 735 // When the dictionary is corrupt, we return 0 which means the word is valid
682 // and has no rules. This means when there is some problem, we'll default 736 // and has no rules. This means when there is some problem, we'll default
683 // to no spellchecking rather than marking everything as misspelled. 737 // to no spellchecking rather than marking everything as misspelled.
684 return 0; 738 return 0;
685 } 739 }
686 NodeReader reader(bdict_data_, bdict_length_, header_->dic_offset, 0); 740 NodeReader reader(bdict_data_, bdict_length_, header_->dic_offset, 0);
687 return reader.FindWord(reinterpret_cast<const unsigned char*>(word), 741 return reader.FindWord(reinterpret_cast<const unsigned char*>(word),
688 affix_indices); 742 affix_indices);
689 } 743 }
690 744
(...skipping 29 matching lines...) Expand all
720 aff_header_->rep_offset); 774 aff_header_->rep_offset);
721 } 775 }
722 776
723 777
724 WordIterator BDictReader::GetAllWordIterator() const { 778 WordIterator BDictReader::GetAllWordIterator() const {
725 NodeReader reader(bdict_data_, bdict_length_, header_->dic_offset, 0); 779 NodeReader reader(bdict_data_, bdict_length_, header_->dic_offset, 0);
726 return WordIterator(reader); 780 return WordIterator(reader);
727 } 781 }
728 782
729 } // namespace hunspell 783 } // namespace hunspell
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698