@@ -123,89 +123,85 @@ var ctx context ctx.input = make([]byte, 0, 8) return decompressor(func(output []byte) (int, error) { var ( - err error - flags byte - readCount, available int + err error + flags byte + rc, available, predicted int ) // Sanity check for space to read into if len(output) == 0 { return 0, nil } // Check whether we have leftover data in the buffer if len(ctx.input) > 0 { - readCount = copy(output, ctx.input) + rc = copy(output, ctx.input) // Check whether we still have leftover data in the buffer :) - if readCount < len(ctx.input) { - ctx.input = ctx.input[:copy(ctx.input, ctx.input[readCount:])] + if rc < len(ctx.input) { + ctx.input = ctx.input[:copy(ctx.input, ctx.input[rc:])] } - return readCount, nil + return rc, nil } // Read the next prediction header - readCount, err = reader.Read(ctx.input[:1]) + rc, err = reader.Read(ctx.input[:1]) // Fail on error unless it is EOF if err != nil && err != io.EOF { return 0, err - } else if readCount == 0 { + } else if rc == 0 { return 0, err } // Extend the buffer, copy the prediction header // and calculate the number of subsequent bytes to read ctx.input = ctx.input[:8] flags = ctx.input[0] - available = 8 - int(bits.Hamming(flags)) + predicted = int(bits.Hamming(flags)) + available = 8 - predicted - // Read the non-predicted bytes according to header. - readCount, err = reader.Read(ctx.input[:available]) + // Read the non-predicted bytes and place them in the end of the buffer + rc, err = reader.Read(ctx.input[predicted:]) retryData: - if readCount < int(available) && err == nil { + if rc < int(available) && err == nil { // Retry the read if we have fewer bytes than what the prediction header indicates var rc int - rc, err = reader.Read(ctx.input[readCount:available]) - readCount += rc + rc, err = reader.Read(ctx.input[predicted+rc:]) + rc += rc goto retryData } // Continue on any error, try to decompress and return it along the result - // Spread the read bytes right to left to avoid overlapping - for i, a := 7, available-1; i >= 0; i-- { - if ((flags >> uint(i)) & 1) == 0 { - ctx.input[i] = ctx.input[a] - a-- - } - } - - // Walk the buffer, fill in the predicted blanks and update the guess table - for i := uint(0); i < 8; i++ { + // Walk the buffer, filling in the predicted blanks, + // relocating read bytes and and updating the guess table + for i, a := uint(0), predicted; i < 8; i++ { if (flags & (1 << i)) > 0 { // Guess succeeded, fill in from the table ctx.input[i] = ctx.table[ctx.hash] - readCount++ + rc++ } else { + // Relocate a read byte + ctx.input[i], a = ctx.input[a], a+1 // Guess failed, update the table ctx.table[ctx.hash] = ctx.input[i] } // Update the hash ctx.hash = (ctx.hash << 4) ^ uint16(ctx.input[i]) } - // readCount now contains the precise amount of populated data - ctx.input = ctx.input[:readCount] + // rc now contains the precise amount of populated data + ctx.input = ctx.input[:rc] available = copy(output, ctx.input) // Check for remaining bytes that dont fit in the output buffer - if available < readCount { + if available < rc { ctx.input = ctx.input[:copy(ctx.input, ctx.input[available:])] } else { // Clear the buffer ctx.input = ctx.input[:0] } return available, err }) }