Bitwise IO: Difference between revisions

64,961 bytes added ,  1 month ago
Replace deprecated functions
(→‎{{header|Go}}: Add Go solution)
(Replace deprecated functions)
 
(43 intermediate revisions by 19 users not shown)
Line 1:
{{task}}[[Category:Bitwise operations]]
{{task}}The aim of this task is to write functions (or create a class if your
language is Object Oriented and you prefer) for reading and writing sequences of
bits, most significant bit first. While the output of a <tt>asciiprint "STRING"</tt> is the ASCII byte sequence
"S", "T", "R", "I", "N", "G", the output of a "print" of the bits sequence
0101011101010 (13 bits) must be 0101011101010; real I/O is performed always
Line 22:
* Errors handling is not mandatory
<br><br>
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">T BitWriter
FileWr out
accumulator = 0
bcount = 0
 
F (fname)
.out = File(fname, WRITE)
 
F _writebit(bit)
I .bcount == 8
.flush()
I bit > 0
.accumulator [|]= 1 << (7 - .bcount)
.bcount++
 
F writebits(bits, =n)
L n > 0
._writebit(bits [&] 1 << (n - 1))
n--
 
F flush()
.out.write_bytes([Byte(.accumulator)])
.accumulator = 0
.bcount = 0
 
F close()
.flush()
.out.close()
 
T BitReader
File input
accumulator = 0
bcount = 0
read = 0
 
F (fname)
.input = File(fname)
 
F _readbit()
I .bcount == 0
V a = .input.read_bytes(at_most' 1)
I !a.empty
.accumulator = a[0]
.bcount = 8
.read = a.len
V rv = (.accumulator [&] (1 << (.bcount - 1))) >> (.bcount - 1)
.bcount--
R rv
 
F readbits(=n)
V v = 0
L n > 0
v = (v << 1) [|] ._readbit()
n--
R v
 
V writer = BitWriter(‘bitio_test.dat’)
V chars = ‘12345abcde’
L(ch) chars
writer.writebits(ch.code, 7)
writer.close()
 
V reader = BitReader(‘bitio_test.dat’)
[Char] charsa
L
V x = reader.readbits(7)
I reader.read == 0
L.break
charsa.append(Char(code' x))
print(charsa.join(‘’))</syntaxhighlight>
 
{{out}}
<pre>
12345abcde
</pre>
 
=={{header|6502 Assembly}}==
===Storing Bytes As ASCII Strings===
This routine converts a byte to a sequence of ASCII zeroes and ones, and stores them in a null-terminated string. Works in Easy6502.
Multiple bytes can be stored this way simply by loading a new value in the accumulator and calling the subroutine again. Since Y is still pointed at the null terminator, no re-adjustment of <code>z_BC</code> or Y is necessary.
<syntaxhighlight lang="6502asm">
define StringRam $1200 ;not actually used in the code, but it's here for clarity.
define z_BC $00 ;fake Z80-style register for pseudo-16-bit operations.
define z_C $00 ;6502 uses the low byte as the reference point for indirect lookups.
define z_B $01 ;high byte
define tempMath $02 ;temp storage of input
define tempBitMask $03 ;temp storage of the bit filter
 
lda #$12
sta z_B
lda #$00
sta z_C ;load address $1200 into zero page memory for an indirect lookup.
 
lda #$0F ;test value
LDY #0 ;initialize offset to zero
 
jsr Hex2BinAscii
brk ;on easy6502 this terminates the program.
 
Hex2BinAscii:
sta tempMath ;store our input, in this case #$0F
lda #%10000000
sta tempBitMask
 
loop_Hex2BinAscii:
lda tempMath ;load input into accumulator.
and tempBitMask ;filter out all bits except the one we are checking this pass of the loop
bne bitIsOne
lda #$30 ;ascii for zero
bne StoreBit
bitIsOne:
lda #$31 ;ascii for one
StoreBit:
sta (z_BC),y ;store in StringRam+Y
loopOverhead:
iny ;y++
lsr tempBitMask ;shift to next bit in sequence
beq loop_Hex2BinAscii ;if mask is zero, we are done. BCC would have worked here as well.
lda #$00 ;load the null terminator
sta (z_BC),y ;store the null terminator after the string
rts</syntaxhighlight>
 
{{out}}
<pre>
1200: 30 30 30 30 31 31 31 31 00
</pre>
 
===Compressing a String of ASCII Zeroes and Ones===
Building on the above, the process can be reversed. The output of the first function becomes the input of the second. Some of the above is repeated, this is to show the two working in sequence.
<syntaxhighlight lang="6502asm">define StringRam $1200
define BitRam $1400
define z_BC $00
define z_C $00
define z_B $01
define z_DE $02
define z_E $02
define z_D $03
define tempMath $04
define tempBitMask $05
define tempY $06
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LDA #0
TAX
TAY ;clear data regs (not needed on Easy6502 but it's a good practice at the start of a program on real hardware)
 
loop_clearRam:
STA $1200,x
STA $1400,x
inx
bne loop_clearRam
 
lda #$12
sta z_B
lda #$00
sta z_C
 
lda #$57
jsr Hex2BinAscii ;store first string
 
lda #$50
jsr Hex2BinAscii ; store second string
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LDA #$12
STA z_B
LDA #$00
STA z_C ; get address of string Ram (this step isn't necessary as they're already loaded but it's here for clarity)
 
LDA #$14
STA z_D
LDA #$00
STA z_E ; get address of destination
 
LDY #$00
STY tempY ; the indices into StringRam and BitRam are different.
 
jsr CompressBits
brk
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Hex2BinAscii:
; this procedure is the same as the above example.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CompressBits:
; takes a stream of ascii zeroes and ones,
; and packs them into a series of bytes.
 
LDX #8 ; repeat 8 times.
LDA #0
STA tempMath ;zero out tempMath
;;;;;;;;;;;;;;;;;;;;;;;;;
loop_CompressBits:
LDA (z_BC),y
beq Terminated ; if the value read is equal to the null terminator, we are done.
; value is assumed to equal #$30 for 0 or #$31 for 1.
ror ; bottom bit of accumulator is rotated into the carry flag.
rol tempMath ; the carry is shifted into the bottom of tempMath.
; repeating this with each successive ascii bit representation
; will preserve the order of the bits. It's hard to explain without drawing a picture
; but trust me it just works.
iny ; next Y
dex
bne loop_CompressBits
;;;;;;;;;;;;;;;;;;;;;;;;;
; loop overhead
tya
pha ; backup source index.
ldy tempY
lda tempMath
sta (z_DE),y
inc tempY ; increment destination index
pla
tay ; restore source index
jmp CompressBits ; back to top
;;;;;;;;;;;;;;;;;;;;;;;;;
Terminated:
rts</syntaxhighlight>
{{out}}
<pre>
1200: 30 31 30 31 30 31 31 31 30 31 30 31 30 30 30 30
1210: 00 (this is the null terminator)
1400: 57 50
</pre>
=={{header|Ada}}==
<langsyntaxhighlight lang="ada">with Ada.Streams; use Ada.Streams;
with Ada.Finalization;
 
Line 43 ⟶ 269:
end record;
overriding procedure Finalize (Stream : in out Bit_Stream);
end Bit_Streams;</langsyntaxhighlight>
The package provides a bit stream interface to a conventional stream. The object of Bit_Stream has a discriminant of any stream type. This stream will be used for physical I/O. Bit_Stream reads and writes arrays of bits. There is no need to have flush procedure, because this is done upon object destruction. The implementation is straightforward, big endian encoding of bits into Stream_Element units is used as required by the task:
<langsyntaxhighlight lang="ada">package body Bit_Streams is
procedure Finalize (Stream : in out Bit_Stream) is
begin
Line 77 ⟶ 303:
end loop;
end Write;
end Bit_Streams;</langsyntaxhighlight>
Example of use:
<langsyntaxhighlight lang="ada">with Ada.Streams.Stream_IO; use Ada.Streams.Stream_IO;
with Bit_Streams; use Bit_Streams;
 
Line 90 ⟶ 316:
1,0,0,0,0,1,1, -- C
1,0,1,0,1,0,1, -- U
1,0,1,0,0,1,1 -- S
);
Data : Bit_Array (ABACUS'Range);
Line 111 ⟶ 337:
raise Data_Error;
end if;
end Test_Bit_Streams;</langsyntaxhighlight>
 
=={{header|ALGOL 68}}==
{{works with|ALGOL 68|Revision 1 - no extensions to language used}}
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}}
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d]}}
<langsyntaxhighlight lang="algol68"># NIBBLEs are of any width, eg 1-bit OR 4-bits etc. #
MODE NIBBLE = STRUCT(INT width, BITS bits);
 
Line 247 ⟶ 472:
example uudecode nibble stream;
example uuencode nibble stream;
example compress 7bit chars</langsyntaxhighlight>
{{out}}
<pre>
Line 265 ⟶ 490:
STRING & ABACUS => 101001110101001010010100100110011101000111010000001001100100000100000110000101000001100001110101011010011
</pre>
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight lang="autohotkey">file = %A_WorkingDir%\z.dat
IfExist, %A_WorkingDir%\z.dat
FileDelete %file%
IfNotEqual ErrorLevel,0, MsgBox Can't delete file "%file%"`nErrorLevel = "%ErrorLevel%"
 
Line 392 ⟶ 616:
Totalread += 0 ; convert to original format
Return TotalRead
}</langsyntaxhighlight>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<langsyntaxhighlight lang="bbcbasic"> file$ = @tmp$ + "bitwise.tmp"
test$ = "Hello, world!"
Line 438 ⟶ 661:
v% = v% << 1 OR (a% >> c%) AND 1
ENDWHILE
= v%</langsyntaxhighlight>
{{out}}
<pre>
Hello, world!
</pre>
=={{header|Binary Lambda Calculus}}==
As explained on https://www.ioccc.org/2012/tromp/hint.html, BLC program
<pre>44 68 16 05 7e 01 17 00 be 55 ff f0 0d c1 8b b2 c1
b0 f8 7c 2d d8 05 9e 09 7f bf b1 48 39 ce 81 ce 80</pre>
compresses a string of ASCII "0"/"1" bytes into an 8x smaller stream of bytes, padding the final byte with 0 bits.
 
=={{header|C}}==
MSB in a byte is considered the "first" bit. Read and write methods somewhat mimic fread and fwrite, though there's no fflush-like function because flushing bits into a file is ill-defined (this whole task is pretty ill-defined). Only way to make sure all bits are written to the file is by detaching the bit filter, just like how closing a file flushes out buffer. There's no limit on read/write size, but caller should ensure the buffer is large enough.
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
Line 453 ⟶ 681:
typedef uint8_t byte;
typedef struct {
FILE *fp;
uint32_t accu;
int bits;
} bit_io_t, *bit_filter;
 
bit_filter b_attach(FILE *f)
{
bit_filter b = malloc(sizeof(bit_io_t));
b->bits = b->accu = 0;
b->fp = f;
return b;
}
 
void b_write(byte *buf, size_t n_bits, size_t shift, bit_filter bf)
{
uint32_t accu = bf->accu;
int bits = bf->bits;
 
buf += shift / 8;
shift %= 8;
 
while (n_bits || bits >= 8) {
while (bits >= 8) {
bits -= 8;
fputc(accu >> bits, bf->fp);
accu &= (1 << bits) - 1;
}
}
while (bits < 8 && n_bits) {
accu = (accu << 1) | (((128 >> shift) & *buf) >> (7 - shift));
--n_bits;
bits++;
if (++shift == 8) {
shift = 0;
buf++;
}
}
}
}
}
}
bf->accu = accu;
bf->bits = bits;
}
 
size_t b_read(byte *buf, size_t n_bits, size_t shift, bit_filter bf)
{
uint32_t accu = bf->accu;
int bits = bf->bits;
int mask, i = 0;
 
buf += shift / 8;
shift %= 8;
 
while (n_bits) {
while (bits && n_bits) {
mask = 128 >> shift;
if (accu & (1 << (bits - 1))) *buf |= mask;
else *buf &= ~mask;
 
n_bits--;
bits--;
 
if (++shift >= 8) {
shift = 0;
buf++;
}
}
}
}
if (!n_bits) break;
accu = (accu << 8) | fgetc(bf->fp);
bits += 8;
}
}
bf->accu = accu;
bf->bits = bits;
 
return i;
}
 
void b_detach(bit_filter bf)
{
if (bf->bits) {
bf->accu <<= 8 - bf->bits;
fputc(bf->accu, bf->fp);
}
}
free(bf);
}
 
int main()
{
unsigned char s[] = "abcdefghijk";
unsigned char s2[11] = {0};
int i;
 
FILE *f = fopen("test.bin", "wb");
bit_filter b = b_attach(f);
/* for each byte in s, write 7 bits skipping 1 */
for (i = 0; i < 10; i++) b_write(s + i, 7, 1, b);
b_detach(b);
fclose(f);
 
/* read 7 bits and expand to each byte of s2 skipping 1 bit */
f = fopen("test.bin", "rb");
b = b_attach(f);
for (i = 0; i < 10; i++) b_read(s2 + i, 7, 1, b);
b_detach(b);
fclose(f);
 
printf("%10s\n", s2); /* should be the same first 10 bytes as in s */
 
return 0;
}</langsyntaxhighlight>
 
=={{header|C sharp|C#}}==
<syntaxhighlight lang="csharp">using System;
using System.IO;
 
public class BitReader
{
uint readData = 0;
int startPosition = 0;
int endPosition = 0;
 
public int InBuffer
{
get { return endPosition - startPosition; }
}
 
private Stream stream;
 
public Stream BaseStream
{
get { return stream; }
}
 
public BitReader(Stream stream)
{
this.stream = stream;
}
 
void EnsureData(int bitCount)
{
int readBits = bitCount - InBuffer;
while (readBits > 0)
{
int b = BaseStream.ReadByte();
 
if (b < 0) throw new InvalidOperationException("Unexpected end of stream");
 
readData |= checked((uint)b << endPosition);
endPosition += 8;
readBits -= 8;
}
}
 
public bool ReadBit()
{
return Read(1) > 0;
}
 
public int Read(int bitCount)
{
EnsureData(bitCount);
 
int result = (int)(readData >> startPosition) & ((1 << bitCount) - 1);
startPosition += bitCount;
if (endPosition == startPosition)
{
endPosition = startPosition = 0;
readData = 0;
}
else if (startPosition >= 8)
{
readData >>= startPosition;
endPosition -= startPosition;
startPosition = 0;
}
 
return result;
}
 
public void Align()
{
endPosition = startPosition = 0;
readData = 0;
}
}
 
public class BitWriter
{
uint data = 0;
int dataLength = 0;
Stream stream;
 
public Stream BaseStream
{
get { return stream; }
}
 
public int BitsToAligment
{
get { return (32 - dataLength) % 8; }
}
 
public BitWriter(Stream stream)
{
this.stream = stream;
}
 
public void WriteBit(bool value)
{
Write(value ? 1 : 0, 1);
}
 
public void Write(int value, int length)
{
uint currentData = data | checked((uint)value << dataLength);
int currentLength = dataLength + length;
while (currentLength >= 8)
{
BaseStream.WriteByte((byte)currentData);
currentData >>= 8;
currentLength -= 8;
}
data = currentData;
dataLength = currentLength;
}
 
public void Align()
{
if (dataLength > 0)
{
BaseStream.WriteByte((byte)data);
 
data = 0;
dataLength = 0;
}
}
}
 
class Program
{
static void Main(string[] args)
{
MemoryStream ms = new MemoryStream();
BitWriter writer = new BitWriter(ms);
writer.WriteBit(true);
writer.Write(5, 3);
writer.Write(0x0155, 11);
writer.Align();
 
ms.Position = 0;
BitReader reader = new BitReader(ms);
Console.WriteLine(reader.ReadBit());
Console.WriteLine(reader.Read(3));
Console.WriteLine(reader.Read(11).ToString("x4"));
reader.Align();
}
}</syntaxhighlight>
=={{header|Common Lisp}}==
 
Common Lisp already has tonnes of bitwise-I/O functionality (remember, folks have written operating systems in Lisp …); in particular, READ-SEQUENCE and WRITE-SEQUENCE neatly handle dumping (VECTOR (UNSIGNED-BYTE 8)) objects directly to/from I/O streams with :ELEMENT-TYPE (UNSIGNED-BYTE 8). This is a fairly robust but not very optimized toolkit that shows off changing between vectors of bytes, vectors of characters, and bit-vectors in a few ways.
 
<langsyntaxhighlight lang="lisp">
(defpackage :rosetta.bitwise-i/o
(:use :common-lisp)
Line 707 ⟶ 1,081:
(finish-output *trace-output*))
 
</syntaxhighlight>
</lang>
{{out}}
<langsyntaxhighlight lang="lisp">
BITWISE-I/O> (bitwise-i/o-demo)
 
Line 736 ⟶ 1,110:
 
⇒ ABORT
</syntaxhighlight>
</lang>
 
=={{header|C sharp|C#}}==
<lang csharp>using System;
using System.IO;
 
public class BitReader
{
uint readData = 0;
int startPosition = 0;
int endPosition = 0;
 
public int InBuffer
{
get { return endPosition - startPosition; }
}
 
private Stream stream;
 
public Stream BaseStream
{
get { return stream; }
}
 
public BitReader(Stream stream)
{
this.stream = stream;
}
 
void EnsureData(int bitCount)
{
int readBits = bitCount - InBuffer;
while (readBits > 0)
{
int b = BaseStream.ReadByte();
 
if (b < 0) throw new InvalidOperationException("Unexpected end of stream");
 
readData |= checked((uint)b << endPosition);
endPosition += 8;
readBits -= 8;
}
}
 
public bool ReadBit()
{
return Read(1) > 0;
}
 
public int Read(int bitCount)
{
EnsureData(bitCount);
 
int result = (int)(readData >> startPosition) & ((1 << bitCount) - 1);
startPosition += bitCount;
if (endPosition == startPosition)
{
endPosition = startPosition = 0;
readData = 0;
}
else if (startPosition >= 8)
{
readData >>= startPosition;
endPosition -= startPosition;
startPosition = 0;
}
 
return result;
}
 
public void Align()
{
endPosition = startPosition = 0;
readData = 0;
}
}
 
public class BitWriter
{
uint data = 0;
int dataLength = 0;
Stream stream;
 
public Stream BaseStream
{
get { return stream; }
}
 
public int BitsToAligment
{
get { return (32 - dataLength) % 8; }
}
 
public BitWriter(Stream stream)
{
this.stream = stream;
}
 
public void WriteBit(bool value)
{
Write(value ? 1 : 0, 1);
}
 
public void Write(int value, int length)
{
uint currentData = data | checked((uint)value << dataLength);
int currentLength = dataLength + length;
while (currentLength >= 8)
{
BaseStream.WriteByte((byte)currentData);
currentData >>= 8;
currentLength -= 8;
}
data = currentData;
dataLength = currentLength;
}
 
public void Align()
{
if (dataLength > 0)
{
BaseStream.WriteByte((byte)data);
 
data = 0;
dataLength = 0;
}
}
}
 
class Program
{
static void Main(string[] args)
{
MemoryStream ms = new MemoryStream();
BitWriter writer = new BitWriter(ms);
writer.WriteBit(true);
writer.Write(5, 3);
writer.Write(0x0155, 11);
writer.Align();
 
ms.Position = 0;
BitReader reader = new BitReader(ms);
Console.WriteLine(reader.ReadBit());
Console.WriteLine(reader.Read(3));
Console.WriteLine(reader.Read(11).ToString("x4"));
reader.Align();
}
}</lang>
 
=={{header|D}}==
{{trans|C}}
<langsyntaxhighlight lang="d">import std.stdio: File;
import core.stdc.stdio: FILE, fputc, fgetc;
import std.string: representation;
Line 1,019 ⟶ 1,245:
// Should be the same chars as 'data'.
result.assumeUTF.writeln;
}</langsyntaxhighlight>
{{out}}
abcdefghijk
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{libheader| System.Classes}}
{{Trans|C#}}
<syntaxhighlight lang="delphi">
program Bitwise_IO;
 
{$APPTYPE CONSOLE}
 
uses
System.SysUtils,
System.Classes;
 
type
TBitReader = class
private
readData: Cardinal;
startPosition: Integer;
endPosition: Integer;
Stream: TStream;
procedure Align;
function BaseStream: TStream;
procedure EnsureData(bitCount: Integer);
function GetInBuffer: Integer;
public
constructor Create(sm: TStream);
function Read(bitCount: Integer): Integer;
function ReadBit: Boolean;
end;
 
TBitWriter = class
private
data: Byte;
dataLength: Integer;
Stream: TStream;
procedure Align;
function BaseStream: TStream;
function BitsToAligment: Integer;
public
constructor Create(sm: TStream);
procedure Write(value, length: Integer);
procedure WriteBit(value: Boolean);
end;
 
function TBitReader.GetInBuffer: Integer;
begin
result := endPosition - startPosition;
end;
 
function TBitReader.BaseStream: TStream;
begin
result := stream;
end;
 
constructor TBitReader.Create(sm: TStream);
begin
Stream := sm;
end;
 
procedure TBitReader.EnsureData(bitCount: Integer);
var
readBits: Integer;
b: Byte;
begin
readBits := bitCount - GetInBuffer;
while readBits > 0 do
begin
BaseStream.Read(b, 1);
readData := readData or (b shl endPosition);
endPosition := endPosition + 8;
readBits := readBits - 8;
end;
end;
 
function TBitReader.ReadBit: Boolean;
begin
Exit(Read(1) > 0);
end;
 
function TBitReader.Read(bitCount: Integer): Integer;
begin
EnsureData(bitCount);
result := (readData shr startPosition) and ((1 shl bitCount) - 1);
startPosition := startPosition + bitCount;
if endPosition = startPosition then
begin
endPosition := ord(startPosition = 0);
readData := 0;
end
else if (startPosition >= 8) then
begin
readData := readData shr startPosition;
endPosition := endPosition - startPosition;
startPosition := 0;
end;
end;
 
procedure TBitReader.Align;
begin
endPosition := ord(startPosition = 0);
readData := 0;
end;
 
function TBitWriter.BaseStream: TStream;
begin
Exit(stream);
end;
 
function TBitWriter.BitsToAligment: Integer;
begin
Exit((32 - dataLength) mod 8);
end;
 
constructor TBitWriter.Create(sm: TStream);
begin
Stream := sm;
end;
 
procedure TBitWriter.WriteBit(value: Boolean);
begin
self.Write(ord(value), 1);
end;
 
procedure TBitWriter.Write(value, length: Integer);
var
currentData: Cardinal;
currentLength: Integer;
begin
currentData := data or (value shl dataLength);
currentLength := dataLength + length;
while currentLength >= 8 do
begin
 
BaseStream.Write(currentData, 1);
currentData := currentData shr 8;
currentLength := currentLength - 8;
end;
data := currentData;
dataLength := currentLength;
end;
 
procedure TBitWriter.Align;
begin
if dataLength > 0 then
begin
BaseStream.Write(data, 1);
data := 0;
dataLength := 0;
end;
end;
 
var
ms: TMemoryStream;
writer: TBitWriter;
reader: TBitReader;
 
begin
ms := TMemoryStream.create();
writer := TBitWriter.create(ms);
writer.WriteBit(true);
writer.Write(5, 3);
writer.Write($0155, 11);
writer.Align();
ms.Position := 0;
reader := TBitReader.create(ms);
writeln(reader.ReadBit());
writeln(reader.Read(3));
writeln(format('0x%.4x', [reader.Read(11)]));
reader.Align();
ms.Free;
writer.Free;
reader.Free;
Readln;
end.</syntaxhighlight>
{{out}}
<pre>
TRUE
5
0x0155
</pre>
 
=={{header|Ecstasy}}==
<syntaxhighlight lang="java">
module BitwiseIO {
class BitReader {
construct(Byte[] bytes) {
this.bits = bytes.toBitArray();
}
 
private Bit[] bits;
private Int index;
 
Int offset { // readable & writable property "offset"
@Override
Int get() {
return index;
}
 
@Override
void set(Int offset) {
assert 0 <= offset < size;
index = offset;
}
}
 
Int size.get() { // read-only property "size"
return bits.size;
}
 
Boolean eof.get() { // read-only property "eof"
return index >= size;
}
 
Bit readBit() {
return eof ? assert:bounds : bits[index++];
}
 
Byte readByte() {
assert:bounds index + 8 <= size as $"eof (offset={index}, size={size}";
Int start = index;
index += 8;
return bits[start ..< index].toByte();
}
}
 
class BitWriter {
private Bit[] bits = new Bit[];
 
BitWriter writeBit(Bit bit) {
bits.add(bit);
return this;
}
 
BitWriter writeByte(Byte byte) {
bits.addAll(byte.toBitArray());
return this;
}
 
Byte[] bytes.get() {
// "zero fill" the bits to the next byte boundary: if the bits don't currently stop at
// a byte boundary, then calc the number of "extra" bits (bits.size & 0x7) and append
// "fill bits" from the end slice of the array of bits in the byte=0
bits += bits.size & 0x7 == 0 ? [] : Byte:0.toBitArray() [bits.size & 0x7 ..< 8];
return bits.toByteArray();
}
}
 
@Inject Console console;
void run() {
Bit[] orig = [0,1,0,1,0,1,1,1,0,1,0,1,0]; // hexadecimal 57 50 (with LSB padding)
 
val out = new BitWriter();
orig.forEach(bit -> out.writeBit(bit));
 
val bytes = out.bytes;
console.print($"bytes written={bytes}"); // 0x5750
 
val in = new BitReader(bytes);
val test = new Bit[orig.size]((Int i) -> in.readBit());
assert test == orig;
}
}
</syntaxhighlight>
 
=={{header|Erlang}}==
<langsyntaxhighlight lang="erlang">-module(bitwise_io).
-compile([export_all]).
 
Line 1,076 ⟶ 1,565:
end,
Decompressed = decompress(Unpadded),
io:format("~p~n",[Decompressed]).</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="erlang">184> bitwise_io:test_bitstring_conversion().
<<"Hello, Rosetta Code!">>: 160
<<145,151,102,205,235,16,82,223,207,47,78,152,80,67,223,147,42,1:4>>: 140
Line 1,085 ⟶ 1,574:
ok
185> bitwise_io:test_file_io().
<<"Hello, Rosetta Code!">></langsyntaxhighlight>
 
=={{header|Forth}}==
The stream status is kept on the stack ( b m ), where b is the character accumulator
Line 1,092 ⟶ 1,580:
with the MSB. (The writing code was originally used for Mandelbrot generation.)
 
<langsyntaxhighlight lang="forth">\ writing
 
: init-write ( -- b m ) 0 128 ;
Line 1,112 ⟶ 1,600:
: read-bit ( b m -- b' m' f )
dup 0= if 2drop init-read then
2dup and swap 2/ swap ;</langsyntaxhighlight>
 
=={{header|FreeBASIC}}==
{{trans|Wren}}
<syntaxhighlight lang="vbnet">Type BitFilter
nombre As String
accu As Integer
bits As Integer
bw As Integer
br As Integer
offset As Integer
End Type
 
Sub openWriter(bf As BitFilter)
bf.bw = Freefile
Open bf.nombre For Binary Access Write As #bf.bw
End Sub
 
Sub openReader(bf As BitFilter)
bf.br = Freefile
Open bf.nombre For Binary Access Read As #bf.br
bf.offset = 0
End Sub
 
Sub escribe(bf As BitFilter, buf() As Byte, start As Integer, nBits As Integer, shift As Integer)
Dim As Integer index = start + (shift \ 8)
shift Mod= 8
While nBits <> 0 Or bf.bits >= 8
While bf.bits >= 8
bf.bits -= 8
Dim As Byte outByte = ((bf.accu Shr bf.bits) And &hFF)
Put #bf.bw, , outByte
Wend
While bf.bits < 8 And nBits <> 0
Dim As Byte b = buf(index)
bf.accu = (bf.accu Shl 1) Or (((128 Shr shift) And b) Shr (7 - shift))
nBits -= 1
bf.bits += 1
shift += 1
If shift = 8 Then
shift = 0
index += 1
End If
Wend
Wend
End Sub
 
Sub lee(bf As BitFilter, buf() As Byte, start As Integer, nBits As Integer, shift As Integer)
Dim As Integer index = start + (shift \ 8)
shift Mod= 8
While nBits <> 0
While bf.bits <> 0 And nBits <> 0
Dim As Byte mask = 128 Shr shift
buf(index) = Iif((bf.accu And (1 Shl (bf.bits - 1))) <> 0, (buf(index) Or mask) And &hFF, (buf(index) And Not mask) And &hFF)
nBits -= 1
bf.bits -= 1
shift += 1
If shift >= 8 Then
shift = 0
index += 1
End If
Wend
If nBits = 0 Then Exit Sub
Dim As Byte inByte
Get #bf.br, bf.offset + 1, inByte
bf.accu = (bf.accu Shl 8) Or inByte
bf.bits += 8
bf.offset += 1
Wend
End Sub
 
Sub closeWriter(bf As BitFilter)
If bf.bits <> 0 Then
bf.accu Shl= (8 - bf.bits)
Dim As Byte outByte = (bf.accu And &hFF)
Put #bf.bw, , outByte
End If
Close #bf.bw
bf.accu = 0
bf.bits = 0
End Sub
 
Sub closeReader(bf As BitFilter)
Close #bf.br
bf.accu = 0
bf.bits = 0
bf.offset = 0
End Sub
 
Dim As Integer i
Dim As BitFilter bf
bf.nombre = "test.bin"
 
' for each byte in s, write 7 bits skipping 1
Dim As Byte s(10) => {Asc("a"), Asc("b"), Asc("c"), Asc("d"), _
Asc("e"), Asc("f"), Asc("g"), Asc("h"), Asc("i"), Asc("j"), Asc("k")}
openWriter(bf)
For i = 0 To Ubound(s)
escribe(bf, s(), i, 7, 1)
Next i
closeWriter(bf)
 
' read 7 bits and expand to each byte of s2 skipping 1 bit
openReader(bf)
Dim As Byte s2(0 To Ubound(s)) = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
For i = 0 To Ubound(s2)
lee(bf, s2(), i, 7, 1)
Next i
closeReader(bf)
 
For i = 0 To Ubound(s2)
Print Chr(s2(i));
Next i
Print
 
Sleep</syntaxhighlight>
{{out}}
<pre>abcdefghijk</pre>
 
=={{header|Go}}==
Line 1,119 ⟶ 1,724:
encoder and decoder internal types
(with LZW specific stuff trimmed).
<langsyntaxhighlight Golang="go">// Package bit provides bit-wise IO to an io.Writer and from an io.Reader.
package bit
 
import (
"bufio"
"errors"
"io"
)
 
Line 1,132 ⟶ 1,737:
 
const (
// LSB is for Least Significant Bits first
LSB Order = iota
// MSB is for Most Significant Bits first
MSB
)
 
Line 1,141 ⟶ 1,746:
 
type writer interface {
io.ByteWriter
Flush() error
}
 
// Writer implements bit-wise writing to an io.Writer.
type Writer struct {
w writer
order Order
write func(uint32, uint) error // writeLSB or writeMSB
bits uint32
nBits uint
err error
}
 
// writeLSB writes `width` bits of `c` in LSB order.
func (w *Writer) writeLSB(c uint32, width uint) error {
w.bits |= c << w.nBits
w.nBits += width
for w.nBits >= 8 {
if err := w.w.WriteByte(uint8(w.bits)); err != nil {
return err
}
}
w.bits >>= 8
w.nBits -= 8
}
}
return nil
}
 
// writeMSB writes `width` bits of `c` in MSB order.
func (w *Writer) writeMSB(c uint32, width uint) error {
w.bits |= c << (32 - width - w.nBits)
w.nBits += width
for w.nBits >= 8 {
if err := w.w.WriteByte(uint8(w.bits >> 24)); err != nil {
return err
}
}
w.bits <<= 8
w.nBits -= 8
}
}
return nil
}
 
// WriteBits writes up to 16 bits of `c` to the underlying writer.
// Even for MSB ordering the bits are taken from the lower bits of `c`.
// (e.g.  WriteBits(0x0f,4) writes four 1 bits).
func (w *Writer) WriteBits(c uint16, width uint) error {
if w.err == nil {
w.err = w.write(uint32(c), width)
}
}
return w.err
}
 
Line 1,198 ⟶ 1,803:
// It does not close the underlying writer.
func (w *Writer) Close() error {
if w.err != nil {
if w.err == errClosed {
return nil
}
}
return w.err
}
}
// Write the final bits (zero padded).
if w.nBits > 0 {
if w.order == MSB {
w.bits >>= 24
}
}
if w.err = w.w.WriteByte(uint8(w.bits)); w.err != nil {
return w.err
}
}
}
}
w.err = w.w.Flush()
if w.err != nil {
return w.err
}
}
 
// Make any future calls to Write return errClosed.
w.err = errClosed
return nil
}
 
// NewWriter returns a new bit Writer that writes completed bytes to `w`.
func NewWriter(w io.Writer, order Order) *Writer {
bw := &Writer{order: order}
switch order {
case LSB:
bw.write = bw.writeLSB
case MSB:
bw.write = bw.writeMSB
default:
bw.err = errors.New("bit writer: unknown order")
return bw
}
}
if byteWriter, ok := w.(writer); ok {
bw.w = byteWriter
} else {
bw.w = bufio.NewWriter(w)
}
}
return bw
}
 
Line 1,247 ⟶ 1,852:
// Reader implements bit-wise reading from an io.Reader.
type Reader struct {
r io.ByteReader
bits uint32
nBits uint
read func(width uint) (uint16, error) // readLSB or readMSB
err error
}
 
func (r *Reader) readLSB(width uint) (uint16, error) {
for r.nBits < width {
x, err := r.r.ReadByte()
if err != nil {
return 0, err
}
}
r.bits |= uint32(x) << r.nBits
r.nBits += 8
}
}
bits := uint16(r.bits & (1<<width - 1))
r.bits >>= width
r.nBits -= width
return bits, nil
}
 
func (r *Reader) readMSB(width uint) (uint16, error) {
for r.nBits < width {
x, err := r.r.ReadByte()
if err != nil {
return 0, err
}
}
r.bits |= uint32(x) << (24 - r.nBits)
r.nBits += 8
}
}
bits := uint16(r.bits >> (32 - width))
r.bits <<= width
r.nBits -= width
return bits, nil
}
 
// ReadBits reads up to 16 bits from the underlying reader.
func (r *Reader) ReadBits(width uint) (uint16, error) {
var bits uint16
if r.err == nil {
bits, r.err = r.read(width)
}
}
return bits, r.err
}
 
Line 1,296 ⟶ 1,901:
// It does not close the underlying reader.
func (r *Reader) Close() error {
if r.err != nil && r.err != errClosed {
return r.err
}
}
r.err = errClosed
return nil
}
 
// NewReader returns a new bit Reader that reads bytes from `r`.
func NewReader(r io.Reader, order Order) *Reader {
br := new(Reader)
switch order {
case LSB:
br.read = br.readLSB
case MSB:
br.read = br.readMSB
default:
br.err = errors.New("bit writer: unknown order")
return br
}
}
if byteReader, ok := r.(io.ByteReader); ok {
br.r = byteReader
} else {
br.r = bufio.NewReader(r)
}
}
return br
}</langsyntaxhighlight>
And a test file (such as <code>bit_test.go</code>):
<langsyntaxhighlight Golang="go">package bit
 
import (
"bytes"
"fmt"
"io"
"log"
)
 
func ExampleWriter_WriteBits() {
var buf bytes.Buffer
bw := NewWriter(&buf, MSB)
bw.WriteBits(0x0f, 4) // Writes 1111
bw.WriteBits(0x00, 1) // 0
bw.WriteBits(0x13, 5) // 1001 1
// Close will flush with zero bits, in this case
// 0000 00
if err := bw.Close(); err != nil {
log.Fatal(err)
}
}
fmt.Printf("%08b", buf.Bytes())
// Output:
// [11110100 11000000]
}
 
func Example() {
const message = "This is a test."
fmt.Printf("%q as bytes: % 02[1]X\n", message, []byte(message))
fmt.Printf(" original bits: %08b\n", []byte(message))
 
// Re-write in 7 bit chunks to buf:
var buf bytes.Buffer
bw := NewWriter(&buf, MSB)
for _, r := range message {
bw.WriteBits(uint16(r), 7) // nolint: errcheck
}
}
if err := bw.Close(); err != nil {
log.Fatal(err)
}
}
fmt.Printf("Written bitstream: %08b\n", buf.Bytes())
fmt.Printf("Written bytes: % 02X\n", buf.Bytes())
 
// Read back in 7 bit chunks:
br := NewReader(&buf, MSB)
var result []byte
for {
v, err := br.ReadBits(7)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
}
break
}
}
if v != 0 {
result = append(result, byte(v))
}
}
}
}
fmt.Printf("Read back as \"%s\"\n", result)
// Output:
// "This is a test." as bytes: 54 68 69 73 20 69 73 20 61 20 74 65 73 74 2E
// original bits: [01010100 01101000 01101001 01110011 00100000 01101001 01110011 00100000 01100001 00100000 01110100 01100101 01110011 01110100 00101110]
// Written bitstream: [10101001 10100011 01001111 00110100 00011010 01111001 10100000 11000010 10000011 10100110 01011110 01111101 00010111 00000000]
// Written bytes: A9 A3 4F 34 1A 79 A0 C2 83 A6 5E 7D 17 00
// Read back as "This is a test."
}</langsyntaxhighlight>
With this test file, running <code>go test -v</code> will compile the package and run the example verifying the output is as listed above in the <code>// Output:</code> comments.
Additionally, <code>godoc -ex</code> will extract the code comments and for documentation and include the examples at the appropriate place
(here the first goes with the <code>WriteBits</code> method and the later with the package documentation).
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">import Data.List
import Data.Char
import Control.Monad
Line 1,422 ⟶ 2,026:
putStrLn $ "Compressed text has " ++ show (length bits `div` 8) ++ " bytes."
putStrLn "Read and decompress:"
putStrLn $ '\t' : bitReader bits</langsyntaxhighlight>
* 7-bits code has lsb leading.
<pre>*Main> :main ["This text is used to illustrate the Rosetta Code task 'bit oriented IO'."]
Line 1,431 ⟶ 2,035:
Read and decompress:
This text is used to illustrate the Rosetta Code task 'bit oriented IO'.</pre>
 
=={{header|J}}==
;Solution
<langsyntaxhighlight lang="j">bitReader =: a. {~ _7 #.\ ({.~ <.&.(%&7)@#)
bitWriter =: , @ ((7$2) & #: @ (a.&i.)), 0 $~ 8 | #</langsyntaxhighlight>
;Usage
Do and undo bit oriented IO:
<langsyntaxhighlight lang="j">text=: 'This text is used to illustrate the Rosetta Code task about ''bit oriented IO''.'
 
bitReader bitWriter text
This text is used to illustrate the Rosetta Code task about 'bit oriented IO'.</langsyntaxhighlight>
Original text length:
<langsyntaxhighlight lang="j"> # text
78</langsyntaxhighlight>
Note: '#' here counts the number of items in its right argument. (In some other languages, # marks the beginning of an in-line comment. J is not one of those languages. Also note that J's command prompt is three spaces. This makes copy&paste easier to use with previously issued commands.)
 
Compressed length:
<langsyntaxhighlight lang="j"> %&8 # bitWriter text
69</langsyntaxhighlight>
Note: this implementation writes the bytes to the session (which is to say, it just gets displayed like any other result. Also, the compressed result is represented as bits - like 1 0 1 0 1... You'll of course need other code when you want to do other things.)
=={{header|Julia}}==
ASCII 7-bit character string compression and decompression, to demonstrate bit twiddling. Implemented as generic IO, so that file handles are usable with the same functions.
<syntaxhighlight lang="julia">
function compress7(inio, outio)
nextwritebyte = read(inio, UInt8) & 0x7f
filled = 7
while !eof(inio)
inbyte = read(inio, UInt8)
write(outio, UInt8(nextwritebyte | inbyte << filled))
nextwritebyte = inbyte >> (8 - filled)
filled = (filled + 7) % 8
if filled == 0
if eof(inio)
break
end
nextwritebyte = read(inio, UInt8) & 0x7f
filled = 7
end
end
if filled != 0
write(outio, UInt8(nextwritebyte))
end
end
 
function expand7(inio, outio)
newbyte = read(inio, UInt8)
write(outio, UInt8(newbyte & 0x7f))
residualbyte::UInt8 = newbyte >> 7
filled = 1
while !eof(inio)
inbyte = read(inio, UInt8)
write(outio, UInt8((residualbyte | inbyte << filled) & 0x7f))
residualbyte = inbyte >> (7 - filled)
filled = (filled + 1) % 7
if filled == 0
write(outio, UInt8(residualbyte & 0x7f))
residualbyte = 0
end
end
end
 
str = b"These bit oriented I/O functions can be used to implement compressors and decompressors."
ins = IOBuffer(str)
outs = IOBuffer()
newouts = IOBuffer()
compress7(ins, outs)
seek(outs,0)
expand7(outs, newouts)
println("Initial string of length $(length(str)): ", String(ins.data))
println("Compressed to length $(length(outs.data)) on line below:\n", String(outs.data))
println("Decompressed string: ", String(newouts.data))
</syntaxhighlight> {{out}} <pre>
Initial string of length 88: These bit oriented I/O functions can be used to implement compressors and decompressors.
Compressed to length 77 on line below:
��A�y����A�6�]n��t��݆����[>��d��<~����|��]
Decompressed string: These bit oriented I/O functions can be used to implement compressors and decompressors.
</pre>
=={{header|Kotlin}}==
{{trans|C}}
<langsyntaxhighlight lang="scala">// version 1.2.31
 
import java.io.File
Line 1,537 ⟶ 2,196:
bf.closeReader()
println(String(s2, Charsets.UTF_8))
}</langsyntaxhighlight>
 
{{out}}
Line 1,543 ⟶ 2,202:
abcdefghijk
</pre>
 
=={{header|Lingo}}==
A "BitArray" class can be implemented by sub-classing ByteArray and extending it with methods that allow to get/set individual bits:
<langsyntaxhighlight lang="lingo">-- parent script "BitArray"
 
property ancestor
Line 1,608 ⟶ 2,266:
delete the last char of res
return res
end</langsyntaxhighlight>
 
Simple compression/decompression functions for 7-bit ASCII strings:
<langsyntaxhighlight lang="lingo">----------------------------------------
-- @param {string} str - ASCII string
-- @return {instance} BitArray
Line 1,647 ⟶ 2,305:
end repeat
return str
end</langsyntaxhighlight>
 
<langsyntaxhighlight lang="lingo">str = "ABC"
ba = crunchASCII(str)
 
Line 1,659 ⟶ 2,317:
 
put decrunchASCII(ba)
-- "ABC"</langsyntaxhighlight>
=={{header|Lua}}==
 
{{works with|Lua|5.1 and later, including LuaJIT}}
 
This code defines two functions that return objects for reading and writing bits from/to strings.
 
<syntaxhighlight lang="lua">local function BitWriter() return {
accumulator = 0, -- For current byte.
bitCount = 0, -- Bits set in current byte.
outChars = {},
 
-- writer:writeBit( bit )
writeBit = function(writer, bit)
writer.bitCount = writer.bitCount + 1
if bit > 0 then
writer.accumulator = writer.accumulator + 2^(8-writer.bitCount)
end
if writer.bitCount == 8 then
writer:_flush()
end
end,
 
-- writer:writeLsb( value, width )
writeLsb = function(writer, value, width)
for i = 1, width do
writer:writeBit(value%2)
value = math.floor(value/2)
end
end,
 
-- dataString = writer:getOutput( )
getOutput = function(writer)
writer:_flush()
return table.concat(writer.outChars)
end,
 
_flush = function(writer)
if writer.bitCount == 0 then return end
 
table.insert(writer.outChars, string.char(writer.accumulator))
writer.accumulator = 0
writer.bitCount = 0
end,
} end
 
local function BitReader(data) return {
bitPosition = 0, -- Absolute position in 'data'.
 
-- bit = reader:readBit( ) -- Returns nil at end-of-data.
readBit = function(reader)
reader.bitPosition = reader.bitPosition + 1
local bytePosition = math.floor((reader.bitPosition-1)/8) + 1
 
local byte = data:byte(bytePosition)
if not byte then return nil end
 
local bitIndex = ((reader.bitPosition-1)%8) + 1
return math.floor(byte / 2^(8-bitIndex)) % 2
end,
 
-- value = reader:readLsb( width ) -- Returns nil at end-of-data.
readLsb = function(reader, width)
local accumulator = 0
 
for i = 1, width do
local bit = reader:readBit()
if not bit then return nil end
 
if bit > 0 then
accumulator = accumulator + 2^(i-1)
end
end
 
return accumulator
end,
} end</syntaxhighlight>
 
Test writing and reading back 7-bit ASCII characters.
 
<syntaxhighlight lang="lua">-- Test writing.
local writer = BitWriter()
local input = "Beautiful moon!"
 
for i = 1, #input do
writer:writeLsb(input:byte(i), 7)
end
 
local data = writer:getOutput() -- May include padding at the end.
 
-- Test reading.
local reader = BitReader(data)
local chars = {}
 
for i = 1, #input do -- Assume the amount of characters is the same as when we wrote the data.
chars[i] = string.char(reader:readLsb(7))
end
 
local output = table.concat(chars)
 
-- Show results.
local hexToBin = {["0"]="0000",["1"]="0001",["2"]="0010",["3"]="0011",
["4"]="0100",["5"]="0101",["6"]="0110",["7"]="0111",
["8"]="1000",["9"]="1001",["a"]="1010",["b"]="1011",
["c"]="1100",["d"]="1101",["e"]="1110",["f"]="1111"}
local function charToHex(c)
return string.format("%02x", c:byte())
end
local function formatBinary(data)
return (data:gsub(".", charToHex)
:gsub(".", hexToBin)
:gsub("........", "%0 "))
end
 
print("In: "..input)
print("Out: "..output)
print("Data: "..formatBinary(data))</syntaxhighlight>
 
{{out}}
 
<pre>
In: Beautiful moon!
Out: Beautiful moon!
Data: 01000011 01001110 00011101 01110010 11110010 11011001 11010111 00110110 00001010 11011111 10111111 01101110 11100001 00000000
</pre>
=={{header|MIPS Assembly}}==
See [[Bitwise IO/MIPS Assembly]]
 
=={{header|Nim}}==
 
<langsyntaxhighlight lang="nim">type
BitWriter * = tuple
file: File
Line 1,714 ⟶ 2,494:
 
result = 0
for ii in 0 .. < nBits :
if stream.nRemain == 0:
stream.nRead = stream.file.readBuffer(stream.bits.addr, 1)
Line 1,754 ⟶ 2,534:
 
assert((dataCtr and 0x7f).uint8 == aByte)
 
inc dataCtr
 
assert(dataCtr == 256)
Line 1,759 ⟶ 2,541:
file.close
 
echo "OK"</langsyntaxhighlight>
 
=={{header|OCaml}}==
The [http://code.google.com/p/ocaml-extlib/ extLib] provides [http://ocaml-extlib.googlecode.com/svn/doc/apiref/IO.html#6_BitsAPI bit oriented IO functions].
<langsyntaxhighlight lang="ocaml">let write_7bit_string ~filename ~str =
let oc = open_out filename in
let ob = IO.output_bits(IO.output_channel oc) in
Line 1,769 ⟶ 2,550:
IO.flush_bits ob;
close_out oc;
;;</langsyntaxhighlight>
 
<langsyntaxhighlight lang="ocaml">let read_7bit_string ~filename =
let ic = open_in filename in
let ib = IO.input_bits(IO.input_channel ic) in
Line 1,780 ⟶ 2,561:
done; ""
with IO.No_more_input ->
(Buffer.contents buf)</langsyntaxhighlight>
 
=={{header|Perl}}==
<syntaxhighlight lang ="perl">#!use /usr/bin/perlstrict;
 
use strict;
 
# $buffer = write_bits(*STDOUT, $buffer, $number, $bits)
sub write_bits :prototype( $$$$ )
{
my ($out, $l, $num, $q) = @_;
$l .= substr(unpack("B*", pack("N", $num)),
-$q);
if ( (length($l) > 8) ) {
my $left = substr($l, 8);
print $out pack("B8", $l);
$l = $left;
}
return $l;
Line 1,802 ⟶ 2,580:
 
# flush_bits(*STDOUT, $buffer)
sub flush_bits :prototype( $$ )
{
my ($out, $b) = @_;
Line 1,809 ⟶ 2,587:
 
# ($val, $buf) = read_bits(*STDIN, $buf, $n)
sub read_bits :prototype( $$$ )
{
my ( $in, $b, $n ) = @_;
Line 1,817 ⟶ 2,595:
if ( $n > 32 ) { return 0; }
while ( length($b) < $n ) {
my $v;
my $red = read($in, $v, 1);
if ( $red < 1 ) { return ( 0, -1 ); }
$b .= substr(unpack("B*", $v), -8);
}
my $bits = "0" x ( 32-$n ) . substr($b, 0, $n);
Line 1,826 ⟶ 2,604:
$b = substr($b, $n);
return ($val, $b);
}</langsyntaxhighlight>
''Crunching'' bytes discarding most significant bit (lossless compression for ASCII and few more!)
<langsyntaxhighlight lang="perl">my $buf = "";
my $c;
while( read(*STDIN, $c, 1) > 0 ) {
$buf = write_bits(*STDOUT, $buf, unpack("C1", $c), 7);
}
flush_bits(*STDOUT, $buf);</langsyntaxhighlight>
Expanding each seven bits to fit a byte (padding the ''eight'' most significant bit with 0):
<langsyntaxhighlight lang="perl">my $buf = "";
my $v;
while(1) {
Line 1,841 ⟶ 2,619:
last if ($buf < 0);
print pack("C1", $v);
}</langsyntaxhighlight>
 
=={{header|Perl 6Phix}}==
<!--<syntaxhighlight lang="phix">(notonline)-->
<lang perl6>sub encode-ascii(Str $s) {
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (file i/o)</span>
my @b = flat $s.ords».fmt("%07b")».comb;
<span style="color: #008080;">enum</span> <span style="color: #000000;">FN</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">V</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">BITS</span> <span style="color: #000080;font-style:italic;">-- fields of a bitwiseioreader/writer</span>
@b.push(0) until @b %% 8; # padding
Buf.new: gather while @b { take reduce * *2+*, (@b.pop for ^8) }
<span style="color: #008080;">function</span> <span style="color: #000000;">new_bitwiseio</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">mode</span><span style="color: #0000FF;">)</span>
}
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mode</span><span style="color: #0000FF;">)</span>
 
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- ie {FN,V=0,BITS=0}</span>
sub decode-ascii(Buf $b) {
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
my @b = flat $b.list».fmt("%08b")».comb;
@b.shift until @b %% 7; # remove padding
<span style="color: #008080;">function</span> <span style="color: #000000;">new_bitwiseiowriter</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">filename</span><span style="color: #0000FF;">)</span>
@b = gather while @b { take reduce * *2+*, (@b.pop for ^7) }
<span style="color: #008080;">return</span> <span style="color: #000000;">new_bitwiseio</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"wb"</span><span style="color: #0000FF;">)</span>
return [~] @b».chr;
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
}
say my $encode = encode-ascii 'STRING';
<span style="color: #008080;">function</span> <span style="color: #000000;">new_bitwiseioreader</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">filename</span><span style="color: #0000FF;">)</span>
say decode-ascii $encode;</lang>
<span style="color: #008080;">return</span> <span style="color: #000000;">new_bitwiseio</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"rb"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">write_bits</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">writer</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bits</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wv</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wb</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">writer</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">p2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bits</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">ch</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">!=</span><span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">2</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">wv</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">wv</span><span style="color: #0000FF;">*</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">+</span><span style="color: #000000;">v</span>
<span style="color: #000000;">wb</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">bits</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">wb</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">8</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">wb</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">8</span>
<span style="color: #000000;">p2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wb</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wv</span><span style="color: #0000FF;">/</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">wv</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">*</span><span style="color: #000000;">p2</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">wv</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">#100</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">wb</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">8</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">writer</span><span style="color: #0000FF;">[</span><span style="color: #000000;">V</span><span style="color: #0000FF;">]=</span> <span style="color: #000000;">wv</span>
<span style="color: #000000;">writer</span><span style="color: #0000FF;">[</span><span style="color: #000000;">BITS</span><span style="color: #0000FF;">]=</span> <span style="color: #000000;">wb</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">writer</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">close_bitwiseiowriter</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">writer</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wv</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wb</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">writer</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">wb</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">wb</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">8</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- sanity check</span>
<span style="color: #000000;">writer</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">write_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">writer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">-</span><span style="color: #000000;">wb</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">writer</span><span style="color: #0000FF;">[</span><span style="color: #000000;">V</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">writer</span><span style="color: #0000FF;">[</span><span style="color: #000000;">BITS</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">writer</span><span style="color: #0000FF;">[</span><span style="color: #000000;">FN</span><span style="color: #0000FF;">]=-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">writer</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">read_bits</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">reader</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">bits</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rv</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rb</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">reader</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">p2</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">bits</span><span style="color: #0000FF;">></span><span style="color: #000000;">rb</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getc</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">reader</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">rv</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rv</span><span style="color: #0000FF;">*</span><span style="color: #000000;">#100</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ch</span>
<span style="color: #000000;">rb</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">8</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">rb</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">bits</span>
<span style="color: #000000;">p2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rb</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rv</span><span style="color: #0000FF;">/</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">rv</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">*</span><span style="color: #000000;">p2</span>
<span style="color: #000000;">reader</span><span style="color: #0000FF;">[</span><span style="color: #000000;">V</span><span style="color: #0000FF;">]=</span> <span style="color: #000000;">rv</span>
<span style="color: #000000;">reader</span><span style="color: #0000FF;">[</span><span style="color: #000000;">BITS</span><span style="color: #0000FF;">]=</span> <span style="color: #000000;">rb</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,</span><span style="color: #000000;">reader</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">as_hexb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">fmt</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"%02x "</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- helper funtion, returns hex string, or binary if fmt="%08b "</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"This is a test."</span>
<span style="color: #000080;font-style:italic;">--constant test = "This is a test"
--constant test = "abcdefghijk"
--constant test = "STRING"
--constant test = "This is an ascii string that will be crunched, written, read and expanded."</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\"%s\" as bytes: %s (length %d)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">test</span><span style="color: #0000FF;">,</span><span style="color: #000000;">as_hexb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" original bits: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">as_hexb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%08b "</span><span style="color: #0000FF;">)})</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">writer</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">new_bitwiseiowriter</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"test.bin"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">writer</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">write_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">writer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">test</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">7</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">writer</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">close_bitwiseiowriter</span><span style="color: #0000FF;">(</span><span style="color: #000000;">writer</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"test.bin"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"rb"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">bytes</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">get_text</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #004600;">GT_WHOLE_FILE</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Written bitstream: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">as_hexb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bytes</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%08b "</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Written bytes: %s (length %d)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">as_hexb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bytes</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bytes</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">reader</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">new_bitwiseioreader</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"test.bin"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">bytes</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,</span><span style="color: #000000;">reader</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">read_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">reader</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">bytes</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">ch</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\"%s\" as bytes: %s (length %d)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">bytes</span><span style="color: #0000FF;">,</span><span style="color: #000000;">as_hexb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bytes</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bytes</span><span style="color: #0000FF;">)})</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
<pre>Buf:0x<03 8b 99 29 4a e5>
"This is a test." as bytes: 54 68 69 73 20 69 73 20 61 20 74 65 73 74 2E (length 15)
STRING</pre>
original bits: 01010100 01101000 01101001 01110011 00100000 01101001 01110011 00100000 01100001 00100000 01110100 01100101 01110011 01110100 00101110
Written bitstream: 10101001 10100011 01001111 00110100 00011010 01111001 10100000 11000010 10000011 10100110 01011110 01111101 00010111 00000000
Written bytes: A9 A3 4F 34 1A 79 A0 C2 83 A6 5E 7D 17 00 (length 14)
"This is a test. " as bytes: 54 68 69 73 20 69 73 20 61 20 74 65 73 74 2E 00 (length 16)
</pre>
Note that the 105(=15*7) bits written out are rounded up/padded to 112(=14*8), reading them back in makes for 16 whole 7-bit values,
which, since 16*7==112, cannot be distinguished from deliberately writing a trailing 7 zero bits. You could, as per the Go example,
simply ignore retrieved zero bytes, but that could fairly obviously create problems for some forms of binary data. A better solution
might be for the data to embed or prefix it's own length. The other four (commented-out) test values do not exhibit this problem.
=={{header|PicoLisp}}==
<syntaxhighlight lang="picolisp">(de write7bitwise (Lst)
(let (Bits 0 Byte)
(for N Lst
(if (=0 Bits)
(setq Bits 7 Byte (* 2 N))
(wr (| Byte (>> (dec 'Bits) N)))
(setq Byte (>> (- Bits 8) N)) ) )
(unless (=0 Bits)
(wr Byte) ) ) )
 
(de read7bitwise ()
(make
(let (Bits 0 Byte)
(while (rd 1)
(let N @
(link
(if (=0 Bits)
(>> (one Bits) N)
(| Byte (>> (inc 'Bits) N)) ) )
(setq Byte (& 127 (>> (- Bits 7) N))) ) )
(when (= 7 Bits)
(link Byte) ) ) ) )</syntaxhighlight>
<syntaxhighlight lang="picolisp">(out 'a (write7bitwise (127 0 127 0 127 0 127 0 127)))
(hd 'a)
(in 'a (println (read7bitwise)))
 
(out 'a (write7bitwise (0 127 0 127 0 127 0 127 0)))
(hd 'a)
(in 'a (println (read7bitwise)))
 
(out 'a (write7bitwise (mapcar char (chop "STRING"))))
(hd 'a)
(println (mapcar char (in 'a (read7bitwise))))</syntaxhighlight>
{{out}}
<pre>00000000 FE 03 F8 0F E0 3F 80 FE .....?..
(127 0 127 0 127 0 127 0)
00000000 01 FC 07 F0 1F C0 7F 00 .......
(0 127 0 127 0 127 0 127)
00000000 A7 52 94 99 D1 C0 .R....
("S" "T" "R" "I" "N" "G")</pre>
=={{header|PL/I}}==
<langsyntaxhighlight PLlang="pl/Ii">declare onebit bit(1) aligned, bs bit (1000) varying aligned;
on endfile (sysin) go to ending;
bs = ''b;
Line 1,873 ⟶ 2,792:
bs = bs || copy('0'b, mod(length(bs), 8) );
/* pad length to a multiple of 8 */
put edit (bs) (b);</langsyntaxhighlight>
Example:
<pre>
Line 1,905 ⟶ 2,824:
1010011101010010100101001001100111010001111010011000110100010100000000
</pre>
 
=={{header|PicoLisp}}==
<lang PicoLisp>(de write7bitwise (Lst)
(let (Bits 0 Byte)
(for N Lst
(if (=0 Bits)
(setq Bits 7 Byte (* 2 N))
(wr (| Byte (>> (dec 'Bits) N)))
(setq Byte (>> (- Bits 8) N)) ) )
(unless (=0 Bits)
(wr Byte) ) ) )
 
(de read7bitwise ()
(make
(let (Bits 0 Byte)
(while (rd 1)
(let N @
(link
(if (=0 Bits)
(>> (one Bits) N)
(| Byte (>> (inc 'Bits) N)) ) )
(setq Byte (& 127 (>> (- Bits 7) N))) ) )
(when (= 7 Bits)
(link Byte) ) ) ) )</lang>
<lang PicoLisp>(out 'a (write7bitwise (127 0 127 0 127 0 127 0 127)))
(hd 'a)
(in 'a (println (read7bitwise)))
 
(out 'a (write7bitwise (0 127 0 127 0 127 0 127 0)))
(hd 'a)
(in 'a (println (read7bitwise)))
 
(out 'a (write7bitwise (mapcar char (chop "STRING"))))
(hd 'a)
(println (mapcar char (in 'a (read7bitwise))))</lang>
{{out}}
<pre>00000000 FE 03 F8 0F E0 3F 80 FE .....?..
(127 0 127 0 127 0 127 0)
00000000 01 FC 07 F0 1F C0 7F 00 .......
(0 127 0 127 0 127 0 127)
00000000 A7 52 94 99 D1 C0 .R....
("S" "T" "R" "I" "N" "G")</pre>
 
=={{header|PureBasic}}==
The bits are read/written with the HSB being read/written first, then each full byte (8 bits) is read/written in succession. Depending on the native integer size the compiler is using, upto 32-bits or 64-bits can be read/written at once. The procedure flushBits() should be called when the reading/writing of bits is completed. If a partial byte is written the bits containing data will begin with the HSB and the padding bits will end with the LSB.
 
As a slight speed modification, the readBits() and writeBits() procedures will attempt to write groups of bits whenever possible.
<langsyntaxhighlight PureBasiclang="purebasic">Structure fileDataBits
bitsToWrite.i
bitsToRead.i
Line 2,071 ⟶ 2,947:
result + "Expanded string = '" + testReadString + "'"
 
MessageRequester("Results", result)</langsyntaxhighlight>
{{out}}
<pre>Original ascii string is 74 bytes.
Line 2,077 ⟶ 2,953:
The expanded string is the same as the original.
Expanded string = 'This is an ascii string that will be crunched, written, read and expanded.'</pre>
 
=={{header|Python}}==
This following code works in both Python 2 & 3. Suggested module file name <tt>bitio.py</tt>.
<langsyntaxhighlight lang="python">class BitWriter(object):
def __init__(self, f):
self.accumulator = 0
Line 2,169 ⟶ 3,044:
chars.append(chr(x))
print(''.join(chars))
</syntaxhighlight>
</lang>
Another usage example showing how to "crunch" an 8-bit byte ASCII stream discarding the most significant "unused" bit...and read it back.
<langsyntaxhighlight lang="python">import sys
import bitio
 
Line 2,180 ⟶ 3,055:
c = sys.stdin.read(1)
o.flush()
</syntaxhighlight>
</lang>
...and to "decrunch" the same stream:
<langsyntaxhighlight lang="python">import sys
import bitio
 
Line 2,190 ⟶ 3,065:
if not r.read: # nothing read
break
sys.stdout.write(chr(x))</langsyntaxhighlight>
 
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 2,254 ⟶ 3,128:
(printf "Decrunched string ~aequal to original.\n"
(if (equal? orig (decrunch "crunched.out")) "" "NOT "))
</syntaxhighlight>
</lang>
 
{{out}}
Line 2,260 ⟶ 3,134:
Decrunched string equal to original.
</pre>
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>sub encode-ascii(Str $s) {
my @b = flat $s.ords».fmt("%07b")».comb;
@b.push(0) until @b %% 8; # padding
Buf.new: gather while @b { take reduce * *2+*, (@b.pop for ^8) }
}
 
sub decode-ascii(Buf $b) {
my @b = flat $b.list».fmt("%08b")».comb;
@b.shift until @b %% 7; # remove padding
@b = gather while @b { take reduce * *2+*, (@b.pop for ^7) }
return [~] @b».chr;
}
say my $encode = encode-ascii 'STRING';
say decode-ascii $encode;</syntaxhighlight>
{{out}}
<pre>Buf:0x<03 8b 99 29 4a e5>
STRING</pre>
=={{header|Red}}==
<syntaxhighlight lang="red">Red [
Title: "Bitwise IO"
Link: http://rosettacode.org/wiki/Bitwise_IO
Source: https://github.com/vazub/rosetta-red
File: "%bitwiseio.red"
Rights: "Copyright (C) 2020 Vasyl Zubko. All rights reserved."
License: "Blue Oak Model License - https://blueoakcouncil.org/license/1.0.0"
Tabs: 4
]
 
str-compress: function [
"Compressesor"
str [string!]
][
buf: copy ""
bit-str: enbase/base str 2
foreach [bit1 bit2 bit3 bit4 bit5 bit6 bit7 bit8] bit-str [
append buf rejoin [bit2 bit3 bit4 bit5 bit6 bit7 bit8]
]
if (pad-bits: (length? buf) // 8) <> 0 [
loop (8 - pad-bits) [append buf "0"]
]
debase/base buf 2
]
 
str-expand: function [
"Decompressor"
bin-hex [binary!]
][
bit-str: enbase/base bin-hex 2
filled: 0
buf: copy []
acc: copy ""
foreach bit bit-str [
append acc bit
filled: filled + 1
if filled = 7 [
append buf debase/base rejoin ["0" acc] 2
clear acc
filled: 0
]
]
if (last buf) = #{00} [take/last buf]
rejoin buf
]
 
; DEMO
in-string: "Red forever!"
compressed: str-compress in-string
expanded: str-expand compressed
prin [
pad "Input (string): " 20 mold in-string newline newline
pad "Input (bits): " 20 enbase/base in-string 2 newline
pad "Compressed (bits): " 20 enbase/base compressed 2 newline newline
pad "Input (hex): " 20 to-binary in-string newline
pad "Compressed (hex): " 20 compressed newline newline
pad "Expanded (string): " 20 mold to-string expanded
]
</syntaxhighlight>
 
{{out}}
<pre>
Input (string): "Red forever!"
 
Input (bits): 010100100110010101100100001000000110011001101111011100100110010101110110011001010111001000100001
Compressed (bits): 1010010110010111001000100000110011011011111110010110010111101101100101111001001000010000
 
Input (hex): #{52656420666F726576657221}
Compressed (hex): #{A597220CDBF965ED979210}
 
Expanded (string): "Red forever!"
</pre>
=={{header|REXX}}==
===version 1===
<langsyntaxhighlight lang="rexx">/* REXX ****************************************************************
* 01.11.2012 Walter Pachl
***********************************************************************/
Line 2,288 ⟶ 3,253:
r=r||x2c(x) /* convert to character */
End /* and append to result */
Say 'r='r /* show result */</langsyntaxhighlight>
{{out}}
<pre>
Line 2,298 ⟶ 3,263:
 
===version 2===
<langsyntaxhighlight lang="rexx">/*REXX pgm encodes/decodes/displays ASCII character strings as (7─bits) binary string.*/
parse arg $; if $=='' then $= 'STRING' /*get optional argument; Use default ? */
say ' input string=' $ /*display the input string to terminal.*/
out= comp($); say ' encoded string=' out /*encode─► 7─bit binary string; display*/
ori= dcomp(out); say ' decoded string=' ori /*decode─► 8─bit char " ; " */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
comp: parse arg x; z=; do j=1 for length(x) /*convert─►right-justified 7-bit binary*/
z= z || right( x2b( c2x( substr(x, j, 1) )), 7)
end /*j*/; L= length(z); return left(z,length(z) L+(8-length(z)L//8)//8, 0)
/*──────────────────────────────────────────────────────────────────────────────────────*/
dcomp: parse arg x; z=; do k=1 by 7 to length(x); _= substr(x, k, 7)
if right(_, 1)==' ' then leave; z= z || x2c( b2x(0 || _) )
end z=z || x2c(/*k*/; b2x(0 || _) ) return z</syntaxhighlight>
end /*k*/; return z</lang>
{{out|output|text=&nbsp; when using the default input:}}
<pre>
Line 2,319 ⟶ 3,283:
decoded string= STRING
</pre>
 
=={{header|Ruby}}==
{{trans|Tcl}}
{{works with|Ruby|1.8.7}}
<langsyntaxhighlight lang="ruby">def crunch(ascii)
bitstring = ascii.bytes.collect {|b| "%07b" % b}.join
[bitstring].pack("B*")
Line 2,357 ⟶ 3,320:
else
puts "fail!"
end</langsyntaxhighlight>
=={{header|Rust}}==
The implementation accepts the number of bits to discard/expand as an argument.
 
<syntaxhighlight lang="rust">pub trait Codec<Input = u8> {
type Output: Iterator<Item = u8>;
 
fn accept(&mut self, input: Input) -> Self::Output;
fn finish(self) -> Self::Output;
}
 
#[derive(Debug)]
pub struct BitDiscard {
buf: u16, // Use the higher byte for storing the leftovers
buf_bits: u8, // How many bits are valid in the buffer
valid_len: u8, // How many bits to keep from the input
shift_len: u8, // Pre-computed shift of the input byte
}
 
impl BitDiscard {
pub fn new(discard: u8) -> Self {
assert!(discard < 8);
 
BitDiscard {
buf: 0,
buf_bits: 0,
valid_len: 8 - discard,
shift_len: 8 + discard,
}
}
}
 
impl Codec<u8> for BitDiscard {
type Output = std::option::IntoIter<u8>;
 
fn accept(&mut self, input: u8) -> Self::Output {
let add = ((input as u16) << self.shift_len) >> self.buf_bits;
self.buf |= add;
self.buf_bits += self.valid_len;
 
let result = if self.buf_bits >= 8 {
let result = (self.buf >> 8) as u8;
self.buf <<= 8;
self.buf_bits -= 8;
Some(result)
} else {
None
};
 
result.into_iter()
}
 
fn finish(self) -> Self::Output {
let result = if self.buf_bits > 0 {
Some((self.buf >> 8) as u8)
} else {
None
};
 
result.into_iter()
}
}
 
#[derive(Debug)]
pub struct BitExpand {
buf: u16, // For storing the leftovers
buf_bits: u8, // How many bits are valid in the buffer
valid_len: u8, // How many bits are valid in the input
shift_len: u8, // How many bits to shift when expanding
}
 
impl BitExpand {
pub fn new(expand: u8) -> Self {
assert!(expand < 8);
 
Self {
buf: 0,
buf_bits: 0,
valid_len: 8 - expand,
shift_len: 8 + expand,
}
}
}
 
impl Codec<u8> for BitExpand {
type Output = BitExpandIter;
 
fn accept(&mut self, input: u8) -> Self::Output {
let add = ((input as u16) << 8) >> self.buf_bits;
self.buf |= add;
self.buf_bits += 8;
let buf = self.buf;
let leftover = self.buf_bits % self.valid_len;
let buf_bits = self.buf_bits - leftover;
self.buf <<= buf_bits;
self.buf_bits = leftover;
 
Self::Output {
buf,
buf_bits,
shift_len: self.shift_len,
valid_len: self.valid_len,
}
}
 
fn finish(self) -> Self::Output {
Self::Output {
buf: 0,
buf_bits: 0,
shift_len: 0,
valid_len: self.valid_len,
}
}
}
 
#[derive(Debug)]
pub struct BitExpandIter {
buf: u16,
buf_bits: u8,
valid_len: u8,
shift_len: u8,
}
 
impl Iterator for BitExpandIter {
type Item = u8;
 
fn next(&mut self) -> Option<u8> {
if self.buf_bits < self.valid_len {
None
} else {
let result = (self.buf >> self.shift_len) as u8;
self.buf <<= self.valid_len;
self.buf_bits -= self.valid_len;
Some(result)
}
}
}
 
fn process_bytes<C: Codec>(mut codec: C, bytes: &[u8]) -> Vec<u8> {
let mut result: Vec<u8> = bytes.iter().flat_map(|byte| codec.accept(*byte)).collect();
codec.finish().for_each(|byte| result.push(byte));
result
}
 
fn print_bytes(bytes: &[u8]) {
for byte in bytes {
print!("{:08b} ", byte);
}
println!();
 
for byte in bytes {
print!("{:02x} ", byte);
}
println!();
}
 
fn main() {
let original = b"STRINGIFY!";
let discard = 1;
print_bytes(&original[..]);
let compressed = process_bytes(BitDiscard::new(discard), &original[..]);
print_bytes(&compressed);
let decompressed = process_bytes(BitExpand::new(discard), &compressed);
print_bytes(&decompressed);
}</syntaxhighlight>
=={{header|Seed7}}==
The Seed7 library [https://seed7.sourceforge.net/libraries/bitdata.htm bitdata.s7i] defines
several functions to do bitwise I/O. Bitwise data can be read from (or written to) a string or a file.
The direction of bits can be from LSB (least significant bit) to MSB (most significant bit) or vice versa.
In the program below the functions
[https://seed7.sourceforge.net/libraries/bitdata.htm#putBitsMsb(inout_file,inout_integer,in_var_integer,in_var_integer) putBitsMsb], [https://seed7.sourceforge.net/libraries/bitdata.htm#openMsbBitStream(in_file) openMsbBitStream] and [https://seed7.sourceforge.net/libraries/bitdata.htm#getBits(inout_msbBitStream,in_integer) getBits] are used.
 
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i";
include "bitdata.s7i";
include "strifile.s7i";
 
const proc: initWriteAscii (inout file: outFile, inout integer: bitPos) is func
begin
outFile.bufferChar := '\0;';
bitPos := 0;
end func;
 
const proc: writeAscii (inout file: outFile, inout integer: bitPos, in string: ascii) is func
local
var char: ch is ' ';
begin
for ch range ascii do
if ch > '\127;' then
raise RANGE_ERROR;
else
putBitsMsb(outFile, bitPos, ord(ch), 7);
end if;
end for;
end func;
 
const proc: finishWriteAscii (inout file: outFile, inout integer: bitPos) is func
begin
putBitsMsb(outFile, bitPos, 0, 7); # Write a terminating NUL char.
write(outFile, chr(ord(outFile.bufferChar)));
end func;
 
const func string: readAscii (inout msbBitStream: aBitStream) is func
result
var string: stri is "";
local
var char: ch is ' ';
begin
while ch <> '\0;' do
ch := chr(getBits(aBitStream, 7));
if ch <> '\0;' then
stri &:= ch;
end if;
end while;
end func;
 
const proc: main is func
local
var file: aFile is STD_NULL;
var integer: bitPos is 0;
var msbBitStream: aBitStream is msbBitStream.value;
begin
aFile := openStriFile;
initWriteAscii(aFile, bitPos);
writeAscii(aFile, bitPos, "Hello, Rosetta Code!");
finishWriteAscii(aFile, bitPos);
seek(aFile, 1);
aBitStream := openMsbBitStream(aFile);
writeln(literal(readAscii(aBitStream)));
end func;</syntaxhighlight>
 
{{out}}
<pre>
"Hello, Rosetta Code!"
</pre>
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
 
proc crunch {ascii} {
Line 2,407 ⟶ 3,603:
} else {
error "not the same"
}</langsyntaxhighlight>
{{out}}
<pre>my ascii string is 74 bytes
the file containing the crunched text is 65 bytes
the expanded string is the same as the original</pre>
=={{header|Wren}}==
{{trans|Kotlin}}
<syntaxhighlight lang="wren">import "io" for File
 
class BitFilter {
construct new(name) {
_name = name
_accu = 0
_bits = 0
}
 
openWriter() {
_bw = File.create(_name)
}
 
openReader() {
_br = File.open(_name)
_offset = 0
}
 
write(buf, start, nBits, shift) {
var index = start + (shift/8).floor
shift = shift % 8
while (nBits != 0 || _bits >= 8) {
while (_bits >= 8) {
_bits = _bits - 8
_bw.writeBytes(String.fromByte((_accu >> _bits) & 255))
}
while (_bits < 8 && nBits != 0) {
var b = buf[index]
_accu = (_accu << 1) | (((128 >> shift) & b) >> (7 - shift))
nBits = nBits - 1
_bits = _bits + 1
shift = shift + 1
if (shift == 8) {
shift = 0
index = index + 1
}
}
}
}
 
read(buf, start, nBits, shift) {
var index = start + (shift/8).floor
shift = shift % 8
while (nBits != 0) {
while (_bits != 0 && nBits != 0) {
var mask = 128 >> shift
if ((_accu & (1 << (_bits - 1))) != 0) {
buf[index] = (buf[index] | mask) & 255
} else {
buf[index] = (buf[index] & ~mask) & 255
}
nBits = nBits - 1
_bits = _bits - 1
shift = shift + 1
if (shift >= 8) {
shift = 0
index = index + 1
}
}
if (nBits == 0) break
var byte = _br.readBytes(1, _offset).bytes[0]
_accu = (_accu << 8) | byte
_bits = _bits + 8
_offset = _offset + 1
}
}
 
closeWriter() {
if (_bits != 0) {
_accu = _accu << (8 - _bits)
_bw.writeBytes(String.fromByte(_accu & 255))
}
_bw.close()
_accu = 0
_bits = 0
}
 
closeReader() {
_br.close()
_accu = 0
_bits = 0
_offset = 0
}
}
 
var s = "abcdefghijk".bytes.toList
var f = "test.bin"
var bf = BitFilter.new(f)
 
/* for each byte in s, write 7 bits skipping 1 */
bf.openWriter()
for (i in 0...s.count) bf.write(s, i, 7, 1)
bf.closeWriter()
 
/* read 7 bits and expand to each byte of s2 skipping 1 bit */
bf.openReader()
var s2 = List.filled(s.count, 0)
for (i in 0...s2.count) bf.read(s2, i, 7, 1)
bf.closeReader()
System.print(s2.map { |b| String.fromByte(b) }.join())</syntaxhighlight>
 
{{out}}
<pre>
abcdefghijk
</pre>
 
=={{header|Z80 Assembly}}==
 
===Uncompressing Packed Bytes into ASCII Zeroes and Ones===
Code is optimized to use what I call a "revolving bit mask" since there is no way to iterate through <code>BIT</code> commands without self-modifying code which is even more difficult to read in my opinion. Using <code>BIT</code> tests without self-modifying code would require the loop to be unrolled.
<syntaxhighlight lang="z80">StoreBinaryString:
;INPUT:
; HL = SOURCE ADDRESS
; DE = OUTPUT STRING RAM
; BC = HOW MANY BYTES OF SOURCE DATA TO CONVERT
ld a,(hl)
push bc
ld b,a ;backup a for later
ld c,%10000000 ;a "revolving bit mask" is used to compare
; each bit of A, in sequence.
loop:
ld a,b ;restore A
and c
ld a,'0' ;get ascii 0 into A. This does not affect the flags!
jr z,skip ;this jump is based on the result of B AND C
inc a ;convert ascii 0 into ascii 1, only if B AND C was nonzero.
skip:
LD (DE),A ;store in output string
inc de ;next byte of output string
rrc c ;shift the bit mask down to the next bit of A
jr nc,loop ;once a 1 is shifted into the carry, we're finished. Otherwise, check next bit.
pop bc
inc hl
dec bc
ld a,b
or c
jp nz,StoreBinaryString
ret</syntaxhighlight>
{{out}}
<pre>
Hexdump (using &57 &50 as input):
 
30 31 30 31 30 31 31 31 01010111
30 31 30 31 30 30 30 30 01010000
</pre>
 
===Compressing a String of ASCII Zeroes and Ones===
<syntaxhighlight lang="z80">CompressBinaryStrings_7bit:
; HL = pointer to output
; DE = pointer to input. Input is assumed to equal &30 or &31
; Usage:
; LD hl,OutputRam
; LD de,InputRam
; CALL CompressBinaryStrings_7bit
; If the string "runs out" before the 8 bit boundary, the rest are rotated into place.
; e.g. input = "0101" then the procedure will RLC until those bits
; are as far left as possible.
 
outerloop:
inc de ;skip bit 7
ld b,7 ;loop counter
innerloop:
ld a,(de)
or a ;compares accumulator to zero. Assumes a null-terminated string.
; Otherwise compare A to your terminator of choice.
 
jr z,HandleEarlyExit
;input is assumed to be &30 or &31, so the least significant bit tells us
; all we need to know. The rest of the byte can be discarded.
 
rra ;rotate the result into the carry
rl (hl) ;rotate it out of the carry into (HL)
inc de
z_djnz innerloop
;a macro that becomes DJNZ <label> on Zilog Z80 and DEC B JR NZ,<label> on Sharp LR35902
 
inc hl ;next output byte
jp outerloop
HandleEarlyExit:
xor a ;LD A,0
cp b ;compare B to zero
ret z ;if B=0, we're done. No need to adjust the last byte
loop_earlyExit
rlc (hl)
z_djnz loop_earlyExit
ret</syntaxhighlight>
 
{{out}}
<pre>
(Tested using input string of "0101011101010". Printing routines left out for brevity but can be added upon request.
 
57 50
</pre>
=={{header|zkl}}==
This code implements two state machines: one that transforms a bit stream (ie a stream of ints with a maximum number of bits) to a byte stream and one does the reverse transform. All streams are considered infinite (eg a file or socket).
 
Bits to bytes:
<langsyntaxhighlight lang="zkl"> // stream of numBits sized ints to bytes, numBits<8
fcn toBytes(n,[(numBits,acc,bitsSoFar)]state){
acc=acc.shiftLeft(numBits) + n; bitsSoFar+=numBits;
Line 2,429 ⟶ 3,822:
state.clear(numBits,acc,bitsSoFar);
r
}</langsyntaxhighlight>
Encode a stream of 6 bit characters:
<langsyntaxhighlight lang="zkl">ns:="THIS IS A TEST".pump(List,"toAsc",'-(0x20));
ns.println(ns.len());
 
Line 2,437 ⟶ 3,830:
cns:=ns.pump(List,toBytes.fp1(state)); // List could be a file or socket or ...
if(state[2]) cns+=toBytes(0,state); // flush
cns.println(cns.len());</langsyntaxhighlight>
{{out}}
<pre>
Line 2,444 ⟶ 3,837:
</pre>
Byte stream to bit stream:
<langsyntaxhighlight lang="zkl"> // stream of bytes to numBits sized ints, 1<numBits<32
fcn fromBytes(n,[(numBits,acc,bitsSoFar,buf)]state){
acc=acc.shiftLeft(8) + n; bitsSoFar+=8;
Line 2,455 ⟶ 3,848:
state.clear(numBits,acc,bitsSoFar,buf);
return(Void.Write,Void.Write,buf); // append contents of buf to result
}</langsyntaxhighlight>
Decode the above stream:
<langsyntaxhighlight lang="zkl">state:=L(6,0,0,L()); // output is six bits wide
r:=cns.pump(List,fromBytes.fp1(state)); // cns could be a file or ...
r.println(r.len());
r.pump(String,'+(0x20),"toChar").println();</langsyntaxhighlight>
{{out}}
<pre>
Line 2,466 ⟶ 3,859:
THIS IS A TEST
</pre>
 
{{omit from|AWK|Traditional AWK has no bitwise operators}}
{{omit from|gnuplot}}
29

edits