@@ -108,6 +108,7 @@ void Input::DetectFormat() {
108108 finish_ (false , " DAX uncompressed size not aligned to sector size" );
109109 } else {
110110 size_ = header->uncompressed_size ;
111+ csoBlockSize_ = DAX_FRAME_SIZE;
111112
112113 const uint32_t frames = static_cast <uint32_t >((size_ + DAX_FRAME_SIZE - 1 ) >> DAX_FRAME_SHIFT);
113114 daxIndex_ = new uint32_t [frames];
@@ -323,22 +324,39 @@ void Input::EnqueueDecompressSector(uint8_t *src, uint32_t len, uint32_t offset,
323324 }
324325 }
325326 }, [this , actualBuf, offset](uv_work_t *req, int status) {
326- if (offset != 0 ) {
327- memmove (actualBuf, actualBuf + offset, SECTOR_SIZE);
328- }
329-
330327 if (!decompressError_.empty ()) {
331328 finish_ (false , decompressError_.c_str ());
332329 pool.Release (actualBuf);
330+ return ;
333331 } else if (status == -1 ) {
334332 finish_ (false , " Decompression work failed" );
335333 pool.Release (actualBuf);
336- } else {
337- callback_ (pos_, actualBuf);
334+ return ;
335+ }
338336
337+ // If the input has a larger block size than SECTOR_SIZE, queue each up here.
338+ // Prevents double decompression of input blocks.
339+ for (uint32_t suboffset = offset; suboffset < csoBlockSize_; suboffset += SECTOR_SIZE) {
340+ const bool lastSubBlock = suboffset + SECTOR_SIZE >= csoBlockSize_;
341+ uint8_t *const subBuf = lastSubBlock ? actualBuf : pool.Alloc ();
342+ if (lastSubBlock) {
343+ memmove (actualBuf, actualBuf + suboffset, SECTOR_SIZE);
344+ } else {
345+ memmove (subBuf, actualBuf + suboffset, SECTOR_SIZE);
346+ }
347+
348+ callback_ (pos_, subBuf);
339349 pos_ += SECTOR_SIZE;
340- ReadSector ();
350+
351+ // We may have filled early. In this case, we have to bail and re-decompress part of this block.
352+ // Luckily, this isn't common.
353+ if (paused_ && !lastSubBlock) {
354+ pool.Release (actualBuf);
355+ break ;
356+ }
341357 }
358+
359+ ReadSector ();
342360 });
343361}
344362
0 commit comments