~poldi1405/go-yenc

db8820d1a641a361e795ea23f26415f1c5eec62d — Moritz Poldrack 7 months ago fdf299f
started work on encoder
5 files changed, 132 insertions(+), 24 deletions(-)

A encdec.go
A encoder.go
A splitting.go
D type.go
D type_test.go
A encdec.go => encdec.go +28 -0
@@ 0,0 1,28 @@
package yenc

import "unsafe"

func yenc(input *[8]byte) []byte {
	var mask [8]bool

	// add 42 (0x2a) to every byte
	*(*uint64)(unsafe.Pointer(&input)) += 0x2a2a2a2a2a2a2a2a

	for i := 0; i < 8; i++ {
		bte := (*(*[8]byte)(unsafe.Pointer(&input)))[i]

		if bte == 0x00 || bte == 0x0A || bte == 0x0D || bte == 0x3D {
			(*(*[8]byte)(unsafe.Pointer(&input)))[i] += uint8(64)
			mask[i] = true
		}
	}

	var result []byte
	for i := 0; i < 8; i++ {
		if mask[i] {
			result = append(result, '=')
		}
		result = append(result, input[i])
	}
	return result
}

A encoder.go => encoder.go +76 -0
@@ 0,0 1,76 @@
package yenc

import (
	"bytes"
	"fmt"
	"hash"
	"hash/crc32"
	"io"
	"sync"
)

type Encoder struct {
	file     io.Writer
	buffer   bytes.Buffer
	writeMtx sync.Mutex

	LineLength int
	BlockSize  int
	CRC        hash.Hash32
}

func NewEncoder(w io.Writer) *Encoder {
	enc := &Encoder{
		file:       w,
		LineLength: 128,
		BlockSize:  0,
		CRC:        crc32.NewIEEE(),
	}
	return enc
}

func (e *Encoder) Write(slice []byte) (int, error) {
	e.writeMtx.Lock()
	defer e.writeMtx.Unlock()

	var bytesWritten int
	remainder := len(slice) % 8
	parts := getParts(&slice)

	maxindex := len(*parts) - 1

	var err error
	var n int
	var encoded []byte

	for i, p := range *parts {
		encoded = yenc(&p)

		if i == maxindex {
			break
		}

		n, err = e.buffer.Write(encoded)
		if err != nil {
			return bytesWritten, fmt.Errorf("failed writing yenc to output-buffer: %v")
		}
		bytesWritten += n
	}

	n, err = e.buffer.Write(encoded[:len(encoded)-(8-remainder)])
	if err != nil {
		return bytesWritten, fmt.Errorf("failed writing yenc to output-buffer: %v")
	}
	bytesWritten += n

	err = e.writeBlock(false)
	if err != nil {
		return n, err
	}

	return bytesWritten, nil
}

func (e *Encoder) writeBlock(closing bool) error {
	return nil
}

A splitting.go => splitting.go +28 -0
@@ 0,0 1,28 @@
package yenc

func getParts(in *[]byte) *[][8]byte {
	var parts [][8]byte

	var part [8]byte
	var i int

	for _, b := range *in {
		part[i] = b
		i++

		if i == 8 {
			parts = append(parts, part)
			i = 0
		}
	}

	if i != 0 {
		for i < 8 {
			part[i] = 0
			i++
		}
		parts = append(parts, part)
	}

	return &parts
}

D type.go => type.go +0 -12
@@ 1,12 0,0 @@
package yenc

type Encoder struct {
	LineLength int
	BlockSize  int
}

func NewEncoder() Encoder {
	return Encoder{
		LineLength: 128,
	}
}

D type_test.go => type_test.go +0 -12
@@ 1,12 0,0 @@
package yenc

import "testing"

func TestNewEncoder(t *testing.T) {
	// Did I say GetLimit was useless? This one is even less useful… but I
	// absolutely hate red lines in the Coverage Report
	y := NewEncoder()
	if y.LineLength != 128 {
		t.Fail()
	}
}