// Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package ccitt import ( "encoding/binary" "io" ) type bitWriter struct { w io.Writer // order is whether to process w's bytes LSB first or MSB first. order Order // The high nBits bits of the bits field hold encoded bits to be written to w. bits uint64 nBits uint32 // bytes[:bw] holds encoded bytes not yet written to w. // Overflow protection is ensured by using a multiple of 8 as bytes length. bw uint32 bytes [1024]uint8 } // flushBits copies 64 bits from b.bits to b.bytes. If b.bytes is then full, it // is written to b.w. func (b *bitWriter) flushBits() error { binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits) b.bits = 0 b.nBits = 0 b.bw += 8 if b.bw < uint32(len(b.bytes)) { return nil } b.bw = 0 if b.order != MSB { reverseBitsWithinBytes(b.bytes[:]) } _, err := b.w.Write(b.bytes[:]) return err } // close finalizes a bitcode stream by writing any // pending bits to bitWriter's underlying io.Writer. func (b *bitWriter) close() error { // Write any encoded bits to bytes. if b.nBits > 0 { binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits) b.bw += (b.nBits + 7) >> 3 } if b.order != MSB { reverseBitsWithinBytes(b.bytes[:b.bw]) } // Write b.bw bytes to b.w. _, err := b.w.Write(b.bytes[:b.bw]) return err } // alignToByteBoundary rounds b.nBits up to a multiple of 8. // If all 64 bits are used, flush them to bitWriter's bytes. func (b *bitWriter) alignToByteBoundary() error { if b.nBits = (b.nBits + 7) &^ 7; b.nBits == 64 { return b.flushBits() } return nil } // writeCode writes a variable length bitcode to b's underlying io.Writer. func (b *bitWriter) writeCode(bs bitString) error { bits := bs.bits nBits := bs.nBits if 64-b.nBits >= nBits { // b.bits has sufficient room for storing nBits bits. b.bits |= uint64(bits) << (64 - nBits - b.nBits) b.nBits += nBits if b.nBits == 64 { return b.flushBits() } return nil } // Number of leading bits that fill b.bits. i := 64 - b.nBits // Fill b.bits then flush and write remaining bits. b.bits |= uint64(bits) >> (nBits - i) b.nBits = 64 if err := b.flushBits(); err != nil { return err } nBits -= i b.bits = uint64(bits) << (64 - nBits) b.nBits = nBits return nil }