cashless2ecash

cashless2ecash: pay with cards for digital cash (experimental)
Log | Files | Refs | README

encoding.go (2277B)


      1 package main
      2 
      3 import (
      4 	"errors"
      5 	"math"
      6 	"strings"
      7 )
      8 
      9 func talerBinaryEncode(byts []byte) string {
     10 
     11 	return encodeCrock(byts)
     12 }
     13 
     14 func talerBinaryDecode(str string) ([]byte, error) {
     15 
     16 	return decodeCrock(str)
     17 }
     18 
     19 func ParseWopid(wopid string) ([]byte, error) {
     20 
     21 	wopidBytes, err := talerBinaryDecode(wopid)
     22 	if err != nil {
     23 		return nil, err
     24 	}
     25 
     26 	if len(wopidBytes) != 32 {
     27 		err = errors.New("invalid wopid")
     28 		return nil, err
     29 	}
     30 
     31 	return wopidBytes, nil
     32 }
     33 
     34 func FormatWopid(wopid []byte) string {
     35 
     36 	return talerBinaryEncode(wopid)
     37 }
     38 
     39 func decodeCrock(e string) ([]byte, error) {
     40 	size := len(e)
     41 	bitpos := 0
     42 	bitbuf := 0
     43 	readPosition := 0
     44 	outLen := int(math.Floor((float64(size) * 5.0) / 8.0))
     45 	out := make([]byte, outLen)
     46 	outPos := 0
     47 
     48 	getValue := func(c byte) (int, error) {
     49 		alphabet := "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
     50 		switch c {
     51 		case 'o', 'O':
     52 			return 0, nil
     53 		case 'i', 'I', 'l', 'L':
     54 			return 1, nil
     55 		case 'u', 'U':
     56 			return 27, nil
     57 		}
     58 
     59 		i := strings.IndexRune(alphabet, rune(c))
     60 		if i > -1 && i < 32 {
     61 			return i, nil
     62 		}
     63 
     64 		return -1, errors.New("encoding error")
     65 	}
     66 
     67 	for readPosition < size || bitpos > 0 {
     68 		if readPosition < size {
     69 			v, err := getValue(e[readPosition])
     70 			if err != nil {
     71 				return nil, err
     72 			}
     73 			readPosition++
     74 			bitbuf = bitbuf<<5 | v
     75 			bitpos += 5
     76 		}
     77 		for bitpos >= 8 {
     78 			d := byte(bitbuf >> (bitpos - 8) & 0xff)
     79 			out[outPos] = d
     80 			outPos++
     81 			bitpos -= 8
     82 		}
     83 		if readPosition == size && bitpos > 0 {
     84 			bitbuf = bitbuf << (8 - bitpos) & 0xff
     85 			if bitbuf == 0 {
     86 				bitpos = 0
     87 			} else {
     88 				bitpos = 8
     89 			}
     90 		}
     91 	}
     92 	return out, nil
     93 }
     94 
     95 func encodeCrock(data []byte) string {
     96 	out := ""
     97 	bitbuf := 0
     98 	bitpos := 0
     99 
    100 	encodeValue := func(value int) byte {
    101 		alphabet := "ABCDEFGHJKMNPQRSTVWXYZ"
    102 		switch {
    103 		case value >= 0 && value <= 9:
    104 			return byte('0' + value)
    105 		case value >= 10 && value <= 31:
    106 			return alphabet[value-10]
    107 		default:
    108 			panic("Invalid value for encoding")
    109 		}
    110 	}
    111 
    112 	for _, b := range data {
    113 		bitbuf = bitbuf<<8 | int(b&0xff)
    114 		bitpos += 8
    115 		for bitpos >= 5 {
    116 			value := bitbuf >> (bitpos - 5) & 0x1f
    117 			out += string(encodeValue(value))
    118 			bitpos -= 5
    119 		}
    120 	}
    121 	if bitpos > 0 {
    122 		bitbuf = bitbuf << (5 - bitpos)
    123 		value := bitbuf & 0x1f
    124 		out += string(encodeValue(value))
    125 	}
    126 	return out
    127 }