@@ -70,11 +70,10 @@ // ... and stage the rest of the data in the buffer ctx.input = append(ctx.input, data[blockSize-bufferLength:]...) return nil } - // TODO allocate this on ctx.buffer ... var buf []byte = make([]byte, 1, blockSize+1) for block := 0; block < len(data)/blockSize; block++ { for i := 0; i < blockSize; i++ { var current byte = data[(block*blockSize)+i] if ctx.table[ctx.hash] == current { @@ -117,45 +116,41 @@ return r(output) } // Returns an io.Reader implementation that wraps the provided io.Reader // and decompresses data according to the predictor algorithm -func Decompressor(wrapped io.Reader) io.Reader { +func Decompressor(reader io.Reader) io.Reader { var ctx context ctx.input = make([]byte, 0, 8) return decompressor(func(output []byte) (int, error) { var ( err error flags byte - readCount int + rc, total 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) - - // 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:])] - } - return readCount, nil - } - - // This is single-iteration only but it is fine according to io.Reader's contract ?! - // TODO - read all bytes from a block based on the hamming weight of the flag - // and just shuffle them for predictions instead of bite-sized reads ;) - - // Read the flags - readCount, err = wrapped.Read(ctx.input[:1]) - if readCount == 0 || err != nil { - return readCount, err + rc = copy(output, ctx.input) + + // Check whether we still have leftover data in the buffer :) + if rc < len(ctx.input) { + ctx.input = ctx.input[:copy(ctx.input, ctx.input[rc:])] + } + return rc, nil + } + + // Read the flags + rc, err = reader.Read(ctx.input[:1]) + if rc == 0 || (err != nil && err != io.EOF) { + return rc, err } ctx.input = ctx.input[:8] flags = ctx.input[0] @@ -163,37 +158,39 @@ for ; i < 8; i++ { if flags&(1< 0 { // Guess was right ctx.input[i] = ctx.table[ctx.hash] } else { - readCount, err = wrapped.Read(ctx.input[i:(i + 1)]) + rc, err = reader.Read(ctx.input[i:(i + 1)]) if err == io.EOF { break } if err != nil { - return readCount, err + return rc, err } - if readCount == 0 { // treat as EoF + if rc == 0 { // treat as EoF break } ctx.table[ctx.hash] = ctx.input[i] } ctx.hash = (ctx.hash << 4) ^ uint16(ctx.input[i]) } - readCount = copy(output, ctx.input[:i]) + rc = copy(output, ctx.input[:i]) + + total += rc // Place any remaining bytes in the buffer - if uint(readCount) < i { - ctx.input = ctx.input[readCount:i] + if uint(rc) < i { + ctx.input = ctx.input[:copy(ctx.input, ctx.input[rc:i])] } else { ctx.input = ctx.input[:0] } - return readCount, nil + return total, err }) }