| // 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 |
| } |