Skip to content

Commit 3e41f5f

Browse files
committed
try the standard structure
1 parent 3923730 commit 3e41f5f

File tree

6 files changed

+94
-234
lines changed

6 files changed

+94
-234
lines changed

.goreleaser.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ builds:
1414
- arm
1515
- arm64
1616
- 386
17+
main: ./cmd/aces
1718
ldflags:
1819
- -s -w
1920
ignore: # problems with build

aces.go

Lines changed: 92 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,108 @@
1-
package main
1+
package aces
22

3-
import (
4-
"fmt"
5-
"io"
6-
"math"
7-
"os"
3+
import "io"
84

9-
"github.com/quackduck/aces/pkg"
10-
)
5+
var BufSize = 16 * 1024
116

12-
var (
13-
encodeHaHa []rune
14-
numOfBits = 0
15-
decode bool
16-
17-
helpMsg = `Aces - Encode in any character set
18-
19-
Usage:
20-
aces <charset> - encode data from STDIN into <charset>
21-
aces -d/--decode <charset> - decode data from STDIN from <charset>
22-
aces -h/--help - print this help message
23-
24-
Aces reads from STDIN for your data and outputs the result to STDOUT. The charset length must be
25-
a power of 2. While decoding, bytes not in the charset are ignored. Aces does not add any padding.
7+
// sliceByteLen slices the byte b such that the result has length len and starting bit start
8+
func sliceByteLen(b byte, start int, len int) byte {
9+
return (b << start) >> byte(8-len)
10+
}
2611

27-
Examples:
28-
echo hello world | aces "<>(){}[]" | aces --decode "<>(){}[]" # basic usage
29-
echo matthew stanciu | aces HhAa | say # make funny sounds (macOS)
30-
aces " X" < /bin/echo # see binaries visually
31-
echo 0100100100100001 | aces -d 01 | aces 01234567 # convert bases
32-
echo Calculus | aces 01 # what's stuff in binary?
33-
echo Aces™ | base64 | aces -d
34-
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ # even decode base64
12+
type BitReader struct {
13+
// set these
14+
chunkLen int
15+
in io.Reader
3516

36-
File issues, contribute or star at github.com/quackduck/aces`
37-
)
17+
// internal vars
18+
buf []byte
19+
bitIdx int
20+
bufN int
21+
}
3822

39-
func main() {
40-
if len(os.Args) == 1 {
41-
fmt.Fprintln(os.Stderr, "error: need at least one argument\n"+helpMsg)
42-
os.Exit(1)
43-
}
44-
if os.Args[1] == "-h" || os.Args[1] == "--help" {
45-
fmt.Println(helpMsg)
46-
return
47-
}
48-
decode = os.Args[1] == "--decode" || os.Args[1] == "-d"
49-
if decode {
50-
if len(os.Args) == 2 {
51-
fmt.Fprintln(os.Stderr, "error: need character set\n"+helpMsg)
52-
os.Exit(1)
53-
}
54-
encodeHaHa = []rune(os.Args[2])
55-
} else {
56-
encodeHaHa = []rune(os.Args[1])
57-
}
58-
numOfBits = int(math.Log2(float64(len(encodeHaHa))))
59-
if 1<<numOfBits != len(encodeHaHa) {
60-
numOfBits = int(math.Round(math.Log2(float64(len(encodeHaHa)))))
61-
fmt.Fprintln(os.Stderr, "error: charset length is not a power of two.\n have:", len(encodeHaHa), "\n want: a power of 2 (nearest is", 1<<numOfBits, "which is", math.Abs(float64(len(encodeHaHa)-1<<numOfBits)), "away)")
62-
os.Exit(1)
23+
func NewBitReader(chunkLen int, in io.Reader) (*BitReader, error) {
24+
//bufSize % bs.chunkLen == 0 so that we never have to read across the buffer boundary
25+
bs := &BitReader{chunkLen: chunkLen, in: in, buf: make([]byte, BufSize-BufSize%chunkLen)}
26+
var err error
27+
bs.bufN, err = bs.in.Read(bs.buf)
28+
if err != nil {
29+
return nil, err
6330
}
31+
return bs, nil
32+
}
6433

65-
if decode {
66-
bw := aces.NewBitWriter(numOfBits, os.Stdout)
67-
buf := make([]byte, 10*1024)
68-
for {
69-
n, err := os.Stdin.Read(buf)
70-
if err != nil {
71-
if err == io.EOF {
72-
break
73-
}
74-
panic(err)
75-
}
76-
for _, c := range []rune(string(buf[:n])) {
77-
for i, char := range encodeHaHa {
78-
if c == char {
79-
err := bw.Write(byte(i))
80-
if err != nil {
81-
panic(err)
82-
return
83-
}
84-
}
85-
}
86-
}
34+
func (bs *BitReader) Read() (byte, error) {
35+
byteNum := bs.bitIdx / 8
36+
bitNum := bs.bitIdx % 8
37+
if byteNum >= bs.bufN { // need to read more
38+
n, err := bs.in.Read(bs.buf)
39+
if err != nil {
40+
return 0, err
8741
}
88-
bw.Flush()
89-
return
42+
bs.bitIdx = bitNum
43+
byteNum = bs.bitIdx / 8
44+
bitNum = bs.bitIdx % 8
45+
bs.bufN = n
9046
}
9147

92-
bs, err := aces.NewBitReader(numOfBits, os.Stdin)
93-
if err != nil {
94-
panic(err)
48+
var result byte
49+
if bitNum+bs.chunkLen > 8 { // want to slice past current byte
50+
firstByte := sliceByteLen(bs.buf[byteNum], bitNum, 8-bitNum)
51+
secondPartLen := bs.chunkLen + bitNum - 8
52+
result = (firstByte << secondPartLen) + sliceByteLen(bs.buf[byteNum+1], 0, secondPartLen)
53+
bs.bitIdx += bs.chunkLen
54+
return result, nil
9555
}
96-
res := make([]byte, 0, 10*1024)
97-
for {
98-
chunk, err := bs.Read()
56+
result = sliceByteLen(bs.buf[byteNum], bitNum, bs.chunkLen)
57+
bs.bitIdx += bs.chunkLen
58+
return result, nil
59+
}
60+
61+
type BitWriter struct {
62+
chunkLen int
63+
out io.Writer
64+
65+
buf []byte
66+
bitIdx int
67+
}
68+
69+
func NewBitWriter(chunkLen int, out io.Writer) *BitWriter {
70+
//bufSize % bw.chunkLen == 0 so that we never have to write across the buffer boundary
71+
return &BitWriter{chunkLen: chunkLen, out: out, buf: make([]byte, BufSize-BufSize%chunkLen)}
72+
}
73+
74+
func (bw *BitWriter) Write(b byte) error {
75+
bitNum := bw.bitIdx % 8
76+
byteNum := bw.bitIdx / 8
77+
if byteNum >= len(bw.buf) {
78+
_, err := bw.out.Write(bw.buf)
9979
if err != nil {
100-
if err == io.EOF {
101-
os.Stdout.Write(res)
102-
os.Stdout.Close()
103-
return
104-
}
105-
panic(err)
106-
}
107-
res = append(res, string(encodeHaHa[chunk])...)
108-
if len(res) > 1024*7/2 {
109-
os.Stdout.Write(res)
110-
res = make([]byte, 0, 2*1024)
80+
return err
11181
}
82+
bw.buf = make([]byte, BufSize-BufSize%bw.chunkLen)
83+
bw.bitIdx = 0
84+
bitNum = 0
85+
byteNum = 0
11286
}
87+
88+
if bitNum+bw.chunkLen > 8 { // write across byte boundary?
89+
// 8-bw.chunkLen is where b's actual data starts from.
90+
bStart := 8 - bw.chunkLen
91+
// space left in current byte
92+
left := 8 - bitNum
93+
94+
bw.buf[byteNum] = bw.buf[byteNum] + sliceByteLen(b, bStart, left)
95+
// bStart + left is up to where b has been read from. (bw.chunkLen+bitNum) - 8 is how many bits go to the next byte.
96+
bw.buf[byteNum+1] = sliceByteLen(b, bStart+left, bw.chunkLen-left) << (bStart + left) // simplified 8 - (bw.chunkLen + bitNum - 8)
97+
} else {
98+
bw.buf[byteNum] = bw.buf[byteNum] + (b << (8 - (bitNum + bw.chunkLen)))
99+
}
100+
bw.bitIdx += bw.chunkLen
101+
return nil
102+
}
103+
104+
// Flush writes the rest of the buffer. Only call this at the end of the stream.
105+
func (bw *BitWriter) Flush() error {
106+
_, err := bw.out.Write(bw.buf[:bw.bitIdx/8])
107+
return err
113108
}

build.sh

Lines changed: 0 additions & 25 deletions
This file was deleted.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
module aces
1+
module github.com/quackduck/aces
22

33
go 1.18

pkg/go.mod

Lines changed: 0 additions & 3 deletions
This file was deleted.

pkg/main.go

Lines changed: 0 additions & 108 deletions
This file was deleted.

0 commit comments

Comments
 (0)