OLD | NEW |
---|---|
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | 1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 /* ***** BEGIN LICENSE BLOCK ***** | 2 /* ***** BEGIN LICENSE BLOCK ***** |
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
4 * | 4 * |
5 * The contents of this file are subject to the Mozilla Public License Version | 5 * The contents of this file are subject to the Mozilla Public License Version |
6 * 1.1 (the "License"); you may not use this file except in compliance with | 6 * 1.1 (the "License"); you may not use this file except in compliance with |
7 * the License. You may obtain a copy of the License at | 7 * the License. You may obtain a copy of the License at |
8 * http://www.mozilla.org/MPL/ | 8 * http://www.mozilla.org/MPL/ |
9 * | 9 * |
10 * Software distributed under the License is distributed on an "AS IS" basis, | 10 * Software distributed under the License is distributed on an "AS IS" basis, |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
91 #define GETN(n, s) \ | 91 #define GETN(n, s) \ |
92 do { \ | 92 do { \ |
93 m_bytesToConsume = (n); \ | 93 m_bytesToConsume = (n); \ |
94 m_state = (s); \ | 94 m_state = (s); \ |
95 } while (0) | 95 } while (0) |
96 | 96 |
97 // Get a 16-bit value stored in little-endian format. | 97 // Get a 16-bit value stored in little-endian format. |
98 #define GETINT16(p) ((p)[1]<<8|(p)[0]) | 98 #define GETINT16(p) ((p)[1]<<8|(p)[0]) |
99 | 99 |
100 // Send the data to the display front-end. | 100 // Send the data to the display front-end. |
101 bool GIFLZWContext::outputRow() | 101 bool GIFLZWContext::outputRow(GIFRow::const_iterator rowBegin) |
102 { | 102 { |
103 int drowStart = irow; | 103 int drowStart = irow; |
104 int drowEnd = irow; | 104 int drowEnd = irow; |
105 | 105 |
106 // Haeberli-inspired hack for interlaced GIFs: Replicate lines while | 106 // Haeberli-inspired hack for interlaced GIFs: Replicate lines while |
107 // displaying to diminish the "venetian-blind" effect as the image is | 107 // displaying to diminish the "venetian-blind" effect as the image is |
108 // loaded. Adjust pixel vertical positions to avoid the appearance of the | 108 // loaded. Adjust pixel vertical positions to avoid the appearance of the |
109 // image crawling up the screen as successive passes are drawn. | 109 // image crawling up the screen as successive passes are drawn. |
110 if (m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass < 4) { | 110 if (m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass < 4) { |
111 unsigned rowDup = 0; | 111 unsigned rowDup = 0; |
(...skipping 29 matching lines...) Expand all Loading... | |
141 | 141 |
142 if ((unsigned)drowEnd >= m_frameContext->height()) | 142 if ((unsigned)drowEnd >= m_frameContext->height()) |
143 drowEnd = m_frameContext->height() - 1; | 143 drowEnd = m_frameContext->height() - 1; |
144 } | 144 } |
145 | 145 |
146 // Protect against too much image data. | 146 // Protect against too much image data. |
147 if ((unsigned)drowStart >= m_frameContext->height()) | 147 if ((unsigned)drowStart >= m_frameContext->height()) |
148 return true; | 148 return true; |
149 | 149 |
150 // CALLBACK: Let the client know we have decoded a row. | 150 // CALLBACK: Let the client know we have decoded a row. |
151 if (!m_client->haveDecodedRow(m_frameContext->frameId(), rowBuffer, m_frameC ontext->width(), | 151 if (!m_client->haveDecodedRow(m_frameContext->frameId(), rowBegin, m_frameCo ntext->width(), |
152 drowStart, drowEnd - drowStart + 1, m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass > 1)) | 152 drowStart, drowEnd - drowStart + 1, m_frameContext->progressiveDisplay() && m_frameContext->interlaced() && ipass > 1)) |
153 return false; | 153 return false; |
154 | 154 |
155 if (!m_frameContext->interlaced()) | 155 if (!m_frameContext->interlaced()) |
156 irow++; | 156 irow++; |
157 else { | 157 else { |
158 do { | 158 do { |
159 switch (ipass) { | 159 switch (ipass) { |
160 case 1: | 160 case 1: |
161 irow += 8; | 161 irow += 8; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
195 } while (irow > (m_frameContext->height() - 1)); | 195 } while (irow > (m_frameContext->height() - 1)); |
196 } | 196 } |
197 return true; | 197 return true; |
198 } | 198 } |
199 | 199 |
200 // Perform Lempel-Ziv-Welch decoding. | 200 // Perform Lempel-Ziv-Welch decoding. |
201 // Returns true if decoding was successful. In this case the block will have bee n completely consumed and/or rowsRemaining will be 0. | 201 // Returns true if decoding was successful. In this case the block will have bee n completely consumed and/or rowsRemaining will be 0. |
202 // Otherwise, decoding failed; returns false in this case, which will always cau se the GIFImageReader to set the "decode failed" flag. | 202 // Otherwise, decoding failed; returns false in this case, which will always cau se the GIFImageReader to set the "decode failed" flag. |
203 bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock) | 203 bool GIFLZWContext::doLZW(const unsigned char* block, size_t bytesInBlock) |
204 { | 204 { |
205 int code; | 205 const size_t width = m_frameContext->width(); |
206 int incode; | |
207 const unsigned char *ch; | |
208 | 206 |
209 if (rowIter == rowBuffer.end()) | 207 if (rowIter == rowBuffer.end()) |
210 return true; | 208 return true; |
211 | 209 |
212 #define OUTPUT_ROW \ | 210 for (const unsigned char* ch = block; bytesInBlock-- > 0; ch++) { |
213 do { \ | |
214 if (!outputRow()) \ | |
215 return false; \ | |
216 rowsRemaining--; \ | |
217 rowIter = rowBuffer.begin(); \ | |
218 if (!rowsRemaining) \ | |
219 return true; \ | |
220 } while (0) | |
221 | |
222 for (ch = block; bytesInBlock-- > 0; ch++) { | |
223 // Feed the next byte into the decoder's 32-bit input buffer. | 211 // Feed the next byte into the decoder's 32-bit input buffer. |
224 datum += ((int) *ch) << bits; | 212 datum += ((int) *ch) << bits; |
225 bits += 8; | 213 bits += 8; |
226 | 214 |
227 // Check for underflow of decoder's 32-bit input buffer. | 215 // Check for underflow of decoder's 32-bit input buffer. |
228 while (bits >= codesize) { | 216 while (bits >= codesize) { |
229 // Get the leading variable-length symbol from the data stream. | 217 // Get the leading variable-length symbol from the data stream. |
230 code = datum & codemask; | 218 int code = datum & codemask; |
231 datum >>= codesize; | 219 datum >>= codesize; |
232 bits -= codesize; | 220 bits -= codesize; |
233 | 221 |
234 // Reset the dictionary to its original state, if requested. | 222 // Reset the dictionary to its original state, if requested. |
235 if (code == clearCode) { | 223 if (code == clearCode) { |
236 codesize = m_frameContext->dataSize() + 1; | 224 codesize = m_frameContext->dataSize() + 1; |
237 codemask = (1 << codesize) - 1; | 225 codemask = (1 << codesize) - 1; |
238 avail = clearCode + 2; | 226 avail = clearCode + 2; |
239 oldcode = -1; | 227 oldcode = -1; |
240 continue; | 228 continue; |
241 } | 229 } |
242 | 230 |
243 // Check for explicit end-of-stream code. | 231 // Check for explicit end-of-stream code. |
244 if (code == (clearCode + 1)) { | 232 if (code == (clearCode + 1)) { |
245 // end-of-stream should only appear after all image data. | 233 // end-of-stream should only appear after all image data. |
246 if (!rowsRemaining) | 234 if (!rowsRemaining) |
247 return true; | 235 return true; |
248 return false; | 236 return false; |
249 } | 237 } |
250 | 238 |
251 if (oldcode == -1) { | 239 const int tempCode = code; |
252 *rowIter++ = suffix[code]; | 240 unsigned short codeLength = 0; |
253 if (rowIter == rowBuffer.end()) | 241 if (code < avail) { |
254 OUTPUT_ROW; | 242 // This is a pre-existing code, so we already know what it |
255 | 243 // encodes. |
256 firstchar = oldcode = code; | 244 codeLength = suffixLength[code]; |
257 continue; | 245 rowIter += codeLength; |
258 } | 246 } else if (code >= avail && oldcode != -1) { |
Peter Kasting
2013/09/03 18:49:45
Why use >= here instead of ==? This allows an att
Alpha Left Google
2013/09/04 23:47:28
Nice catch. I didn't realize tempCode would mess u
| |
259 | 247 // This is a new code just being added to the dictionary. |
260 incode = code; | 248 // It must encode the contents of the previous code, plus |
261 if (code >= avail) { | 249 // the first character of the previous code again. |
262 stack[stackp++] = firstchar; | 250 codeLength = suffixLength[oldcode] + 1; |
251 rowIter += codeLength; | |
252 *--rowIter = firstchar; | |
Peter Kasting
2013/09/03 18:49:45
Nit: This subtraction isn't necessary... maybe
co
Alpha Left Google
2013/09/04 23:47:28
I think my original code was the second one but I
Peter Kasting
2013/09/05 06:13:01
OK. I'm not sure how any of these reflect the com
| |
263 code = oldcode; | 253 code = oldcode; |
264 | 254 } else { |
265 if (stackp == MAX_BYTES) | 255 // This is an invalid code. The dictionary is just initialized |
266 return false; | 256 // and the code is incomplete. We don't know how to handle |
257 // this case. | |
258 return false; | |
267 } | 259 } |
268 | 260 |
269 while (code >= clearCode) { | 261 while (code >= clearCode) { |
270 if (code >= MAX_BYTES || code == prefix[code]) | 262 *--rowIter = suffix[code]; |
271 return false; | |
272 | |
273 // Even though suffix[] only holds characters through suffix[ava il - 1], | |
274 // allowing code >= avail here lets us be more tolerant of malfo rmed | |
275 // data. As long as code < MAX_BYTES, the only risk is a garbled image, | |
276 // which is no worse than refusing to display it. | |
277 stack[stackp++] = suffix[code]; | |
278 code = prefix[code]; | 263 code = prefix[code]; |
279 | |
280 if (stackp == MAX_BYTES) | |
281 return false; | |
282 } | 264 } |
283 | 265 |
284 stack[stackp++] = firstchar = suffix[code]; | 266 *--rowIter = firstchar = suffix[code]; |
285 | 267 |
286 // Define a new codeword in the dictionary. | 268 // Define a new codeword in the dictionary only if the |
287 if (avail < 4096) { | 269 // dictionary is not in initial state. |
Peter Kasting
2013/09/03 18:49:45
Nit: This comment isn't actually correct (checking
Alpha Left Google
2013/09/04 23:47:28
Done.
| |
270 if (avail < MAX_DICTIONARY_ENTRIES && oldcode != -1) { | |
288 prefix[avail] = oldcode; | 271 prefix[avail] = oldcode; |
289 suffix[avail] = firstchar; | 272 suffix[avail] = firstchar; |
290 avail++; | 273 suffixLength[avail] = suffixLength[oldcode] + 1; |
274 ++avail; | |
291 | 275 |
292 // If we've used up all the codewords of a given length | 276 // If we've used up all the codewords of a given length |
293 // increase the length of codewords by one bit, but don't | 277 // increase the length of codewords by one bit, but don't |
294 // exceed the specified maximum codeword size of 12 bits. | 278 // exceed the specified maximum codeword size. |
295 if ((!(avail & codemask)) && (avail < 4096)) { | 279 if ((!(avail & codemask)) && (avail < MAX_DICTIONARY_ENTRIES)) { |
Peter Kasting
2013/09/03 18:49:45
Nit: No parens necessary around unary operator. I
Alpha Left Google
2013/09/04 23:47:28
Done.
| |
296 codesize++; | 280 ++codesize; |
297 codemask += avail; | 281 codemask += avail; |
298 } | 282 } |
299 } | 283 } |
300 oldcode = incode; | 284 oldcode = tempCode; |
285 rowIter += codeLength; | |
301 | 286 |
302 // Copy the decoded data out to the scanline buffer. | 287 // Output as many rows as possible. |
303 do { | 288 GIFRow::iterator rowBegin = rowBuffer.begin(); |
304 *rowIter++ = stack[--stackp]; | 289 for (; rowBegin + width <= rowIter; rowBegin += width) { |
305 if (rowIter == rowBuffer.end()) | 290 if (!outputRow(rowBegin)) |
306 OUTPUT_ROW; | 291 return false; |
307 } while (stackp > 0); | 292 rowsRemaining--; |
293 if (!rowsRemaining) | |
294 return true; | |
295 } | |
296 | |
297 if (rowBegin != rowBuffer.begin()) { | |
298 // Move the remaining bytes to the beginning of the buffer. | |
299 const size_t bytesToCopy = rowIter - rowBegin; | |
300 memcpy(rowBuffer.begin(), rowBegin, bytesToCopy); | |
301 rowIter = rowBuffer.begin() + bytesToCopy; | |
302 } | |
308 } | 303 } |
309 } | 304 } |
310 | |
311 return true; | 305 return true; |
312 } | 306 } |
313 | 307 |
314 void GIFColorMap::buildTable(const unsigned char* data, size_t length) | 308 void GIFColorMap::buildTable(const unsigned char* data, size_t length) |
315 { | 309 { |
316 if (!m_isDefined || !m_table.isEmpty()) | 310 if (!m_isDefined || !m_table.isEmpty()) |
317 return; | 311 return; |
318 | 312 |
319 RELEASE_ASSERT(m_position + m_colors * GIF_COLORS <= length); | 313 RELEASE_ASSERT(m_position + m_colors * BYTES_PER_COLORMAP_ENTRY <= length); |
320 const unsigned char* srcColormap = data + m_position; | 314 const unsigned char* srcColormap = data + m_position; |
321 m_table.resize(m_colors); | 315 m_table.resize(m_colors); |
322 for (Table::iterator iter = m_table.begin(); iter != m_table.end(); ++iter) { | 316 for (Table::iterator iter = m_table.begin(); iter != m_table.end(); ++iter) { |
323 *iter = SkPackARGB32NoCheck(255, srcColormap[0], srcColormap[1], srcColo rmap[2]); | 317 *iter = SkPackARGB32NoCheck(255, srcColormap[0], srcColormap[1], srcColo rmap[2]); |
324 srcColormap += GIF_COLORS; | 318 srcColormap += BYTES_PER_COLORMAP_ENTRY; |
325 } | 319 } |
326 } | 320 } |
327 | 321 |
328 // Perform decoding for this frame. frameDecoded will be true if the entire fram e is decoded. | 322 // Perform decoding for this frame. frameDecoded will be true if the entire fram e is decoded. |
329 // Returns false if a decoding error occurred. This is a fatal error and causes the GIFImageReader to set the "decode failed" flag. | 323 // Returns false if a decoding error occurred. This is a fatal error and causes the GIFImageReader to set the "decode failed" flag. |
330 // Otherwise, either not enough data is available to decode further than before, or the new data has been decoded successfully; returns true in this case. | 324 // Otherwise, either not enough data is available to decode further than before, or the new data has been decoded successfully; returns true in this case. |
331 bool GIFFrameContext::decode(const unsigned char* data, size_t length, WebCore:: GIFImageDecoder* client, bool* frameDecoded) | 325 bool GIFFrameContext::decode(const unsigned char* data, size_t length, WebCore:: GIFImageDecoder* client, bool* frameDecoded) |
332 { | 326 { |
333 m_localColorMap.buildTable(data, length); | 327 m_localColorMap.buildTable(data, length); |
334 | 328 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
449 | 443 |
450 // CALLBACK: Inform the decoderplugin of our size. | 444 // CALLBACK: Inform the decoderplugin of our size. |
451 // Note: A subsequent frame might have dimensions larger than the "s creen" dimensions. | 445 // Note: A subsequent frame might have dimensions larger than the "s creen" dimensions. |
452 if (m_client && !m_client->setSize(m_screenWidth, m_screenHeight)) | 446 if (m_client && !m_client->setSize(m_screenWidth, m_screenHeight)) |
453 return false; | 447 return false; |
454 | 448 |
455 const size_t globalColorMapColors = 2 << (currentComponent[4] & 0x07 ); | 449 const size_t globalColorMapColors = 2 << (currentComponent[4] & 0x07 ); |
456 | 450 |
457 if ((currentComponent[4] & 0x80) && globalColorMapColors > 0) { /* g lobal map */ | 451 if ((currentComponent[4] & 0x80) && globalColorMapColors > 0) { /* g lobal map */ |
458 m_globalColorMap.setTablePositionAndSize(dataPosition, globalCol orMapColors); | 452 m_globalColorMap.setTablePositionAndSize(dataPosition, globalCol orMapColors); |
459 GETN(GIF_COLORS * globalColorMapColors, GIFGlobalColormap); | 453 GETN(BYTES_PER_COLORMAP_ENTRY * globalColorMapColors, GIFGlobalC olormap); |
460 break; | 454 break; |
461 } | 455 } |
462 | 456 |
463 GETN(1, GIFImageStart); | 457 GETN(1, GIFImageStart); |
464 break; | 458 break; |
465 } | 459 } |
466 | 460 |
467 case GIFGlobalColormap: { | 461 case GIFGlobalColormap: { |
468 m_globalColorMap.setDefined(); | 462 m_globalColorMap.setDefined(); |
469 GETN(1, GIFImageStart); | 463 GETN(1, GIFImageStart); |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
687 // frame can be progressively displayed. | 681 // frame can be progressively displayed. |
688 // FIXME: It is possible that a non-transparent frame | 682 // FIXME: It is possible that a non-transparent frame |
689 // can be interlaced and progressively displayed. | 683 // can be interlaced and progressively displayed. |
690 currentFrame->setProgressiveDisplay(currentFrameIsFirstFrame()); | 684 currentFrame->setProgressiveDisplay(currentFrameIsFirstFrame()); |
691 | 685 |
692 const bool isLocalColormapDefined = currentComponent[8] & 0x80; | 686 const bool isLocalColormapDefined = currentComponent[8] & 0x80; |
693 if (isLocalColormapDefined) { | 687 if (isLocalColormapDefined) { |
694 // The three low-order bits of currentComponent[8] specify the b its per pixel. | 688 // The three low-order bits of currentComponent[8] specify the b its per pixel. |
695 const size_t numColors = 2 << (currentComponent[8] & 0x7); | 689 const size_t numColors = 2 << (currentComponent[8] & 0x7); |
696 currentFrame->localColorMap().setTablePositionAndSize(dataPositi on, numColors); | 690 currentFrame->localColorMap().setTablePositionAndSize(dataPositi on, numColors); |
697 GETN(GIF_COLORS * numColors, GIFImageColormap); | 691 GETN(BYTES_PER_COLORMAP_ENTRY * numColors, GIFImageColormap); |
698 break; | 692 break; |
699 } | 693 } |
700 | 694 |
701 GETN(1, GIFLZWStart); | 695 GETN(1, GIFLZWStart); |
702 break; | 696 break; |
703 } | 697 } |
704 | 698 |
705 case GIFImageColormap: { | 699 case GIFImageColormap: { |
706 ASSERT(!m_frames.isEmpty()); | 700 ASSERT(!m_frames.isEmpty()); |
707 m_frames.last()->localColorMap().setDefined(); | 701 m_frames.last()->localColorMap().setDefined(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
751 if (m_frames.isEmpty() || m_frames.last()->isComplete()) | 745 if (m_frames.isEmpty() || m_frames.last()->isComplete()) |
752 m_frames.append(adoptPtr(new GIFFrameContext(m_frames.size()))); | 746 m_frames.append(adoptPtr(new GIFFrameContext(m_frames.size()))); |
753 } | 747 } |
754 | 748 |
755 // FIXME: Move this method to close to doLZW(). | 749 // FIXME: Move this method to close to doLZW(). |
756 bool GIFLZWContext::prepareToDecode() | 750 bool GIFLZWContext::prepareToDecode() |
757 { | 751 { |
758 ASSERT(m_frameContext->isDataSizeDefined() && m_frameContext->isHeaderDefine d()); | 752 ASSERT(m_frameContext->isDataSizeDefined() && m_frameContext->isHeaderDefine d()); |
759 | 753 |
760 // Since we use a codesize of 1 more than the datasize, we need to ensure | 754 // Since we use a codesize of 1 more than the datasize, we need to ensure |
761 // that our datasize is strictly less than the MAX_LZW_BITS value (12). | 755 // that our datasize is strictly less than the MAX_DICTIONARY_ENTRY_BITS. |
762 // This sets the largest possible codemask correctly at 4095. | 756 if (m_frameContext->dataSize() >= MAX_DICTIONARY_ENTRY_BITS) |
763 if (m_frameContext->dataSize() >= MAX_LZW_BITS) | |
764 return false; | 757 return false; |
765 clearCode = 1 << m_frameContext->dataSize(); | 758 clearCode = 1 << m_frameContext->dataSize(); |
766 if (clearCode >= MAX_BYTES) | |
767 return false; | |
768 | |
769 avail = clearCode + 2; | 759 avail = clearCode + 2; |
770 oldcode = -1; | 760 oldcode = -1; |
771 codesize = m_frameContext->dataSize() + 1; | 761 codesize = m_frameContext->dataSize() + 1; |
772 codemask = (1 << codesize) - 1; | 762 codemask = (1 << codesize) - 1; |
773 datum = bits = 0; | 763 datum = bits = 0; |
774 ipass = m_frameContext->interlaced() ? 1 : 0; | 764 ipass = m_frameContext->interlaced() ? 1 : 0; |
775 irow = 0; | 765 irow = 0; |
776 | 766 |
777 // Initialize output row buffer. | 767 // We want to know the longest sequence encodable by a dictionary with |
778 rowBuffer.resize(m_frameContext->width()); | 768 // MAX_DICTIONARY_ENTRIES entries. If we ignore the need to encode the base |
769 // values themselves at the beginning of the dictionary, as well as the need | |
770 // for a clear code or a termination code, we could use every entry to | |
771 // encode a series of multiple values. If the input value stream looked | |
772 // like "AAAAA..." (a long string of just one value), the first dictionary | |
773 // entry would encode AA, the next AAA, the next AAAA, and so forth. Thus | |
774 // the longest sequence would be MAX_DICTIONARY_ENTRIES + 1 values. | |
775 // | |
776 // However, we have to account for reserved entries. The first |datasize| | |
777 // bits are reserved for the base values, and the next two entries are | |
778 // reserved for the clear code and termination code. In theory a GIF can | |
779 // set the datasize to 0, meaning we have just two reserved entries, making | |
780 // the longest sequence (MAX_DICTIONARY_ENTIRES + 1) - 2 values long. Since | |
781 // each value is a byte, this is also the number of bytes in the longest | |
782 // encodable sequence. | |
783 const size_t maxBytes = MAX_DICTIONARY_ENTRIES - 1; | |
784 | |
785 // Now allocate the output buffer. We decode directly into this buffer | |
786 // until we have at least one row worth of data, then call outputRow(). | |
787 // This means worst case we may have (row width - 1) bytes in the buffer | |
788 // and then decode a sequence |maxBytes| long to append. | |
789 rowBuffer.resize(m_frameContext->width() - 1 + maxBytes); | |
779 rowIter = rowBuffer.begin(); | 790 rowIter = rowBuffer.begin(); |
780 rowsRemaining = m_frameContext->height(); | 791 rowsRemaining = m_frameContext->height(); |
781 | 792 |
782 // Clearing the whole suffix table lets us be more tolerant of bad data. | 793 // Clearing the whole suffix table lets us be more tolerant of bad data. |
783 memset(suffix, 0, sizeof(suffix)); | 794 for (int i = 0; i < clearCode; ++i) { |
784 | |
785 // Clearing the whole prefix table to prevent uninitialized access. | |
786 memset(prefix, 0, sizeof(prefix)); | |
787 for (int i = 0; i < clearCode; i++) | |
788 suffix[i] = i; | 795 suffix[i] = i; |
789 stackp = 0; | 796 suffixLength[i] = 1; |
797 } | |
790 return true; | 798 return true; |
791 } | 799 } |
OLD | NEW |