package extraioimport ()// UnpadReader is an io.Reader that unpads padding from PadReader. It validates// the padding on EOF and returns an error if it is invalid.typeUnpadReaderstruct {readerTailReaderblockSizeuint8incompleteint// mutablelastBlock []byte// mutable}// NewUnpadReader returns a new reader that unpads r using the given block size.// If blockSize is zero, UnpadReader is a no-op, i.e. it does not attempt to// remove padding from the underlying reader.func ( io.Reader, uint8) *UnpadReader {var []byteif != 0 { = make([]byte, 0, ) }return &UnpadReader{reader: TailReader{reader: ,buf: , },blockSize: , }}// Reset resets the reader’s state.func ( *UnpadReader) () { .incomplete = 0 .lastBlock = nil .reader.Reset()}// Read implements the io.Reader interface. It reads from the underlying// io.Reader until EOF and then validates and removes padding from the last// block.func ( *UnpadReader) ( []byte) (int, error) {if .lastBlock != nil {return .unpad() } , := .reader.Read()if .blockSize == 0 {return , }if > 0 { := int(.blockSize) .incomplete += % .incomplete %= }if != io.EOF {return , }// Check that all read bytes are divisible into blocks (i.e. we are not // at the incomplete block).if .incomplete != 0 {return , io.ErrUnexpectedEOF }// We call Tail after checking for incomplete blocks in previously read // bytes since it may linearize the underlying bufffer before returning // it. This saves us a few CPU cycles needed to rotate the ring buffer // that would otherwise be unused. // // Note that 0 <= len(lastBlock) <= r.blockSize <= math.MaxUint8. := .reader.Tail()// Check that the last block is also complete. If not, we have an // unexpected EOF.ifuint8(len()) != .blockSize {return , io.ErrUnexpectedEOF }// Check that padding fill byte is within the block size. := [len()-1]if > .blockSize || == 0 {return , io.ErrUnexpectedEOF }// Check that padding is filled with same bytes. , := unpadPayload(, )if ! {return , io.ErrUnexpectedEOF } .lastBlock = , := .unpad([:])return + , }// unpad writes remaining payload to p.func ( *UnpadReader) ( []byte) (int, error) { := copy(, .lastBlock) .lastBlock = .lastBlock[:]iflen(.lastBlock) == 0 { .Reset()return , io.EOF }return , nil}// unpadPayload validates that buf is padded with fillByte bytes and returns the// unpadded payload.func ( []byte, byte) ([]byte, bool) { := int()iflen() < {returnnil, false } := len() - := [:]for , := range {if == {continue }returnnil, false }return [:], true}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)