Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix for #220 bcd length encoding #221

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions encoding/ascii.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ var (

type asciiEncoder struct{}

func (e asciiEncoder) Encode(data []byte) ([]byte, error) {
func (e asciiEncoder) Encode(data []byte) ([]byte, int, error) {
var out []byte
for _, r := range data {
if r > 127 {
return nil, utils.NewSafeError(fmt.Errorf("invalid ASCII char: '%s'", string(r)), "failed to perform ASCII encoding")
return nil, 0, utils.NewSafeError(fmt.Errorf("invalid ASCII char: '%s'", string(r)), "failed to perform ASCII encoding")
}
out = append(out, r)
}

return out, nil
return out, len(out), nil
}

func (e asciiEncoder) Decode(data []byte, length int) ([]byte, int, error) {
Expand Down
4 changes: 2 additions & 2 deletions encoding/ascii_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ func TestASCII(t *testing.T) {
})

t.Run("Encode", func(t *testing.T) {
res, err := enc.Encode([]byte("hello"))
res, _, err := enc.Encode([]byte("hello"))

require.NoError(t, err)
require.Equal(t, []byte("hello"), res)

_, err = enc.Encode([]byte("hello, 世界!"))
_, _, err = enc.Encode([]byte("hello, 世界!"))
require.Error(t, err)
require.EqualError(t, err, "failed to perform ASCII encoding")
})
Expand Down
9 changes: 6 additions & 3 deletions encoding/bcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ var (

type bcdEncoder struct{}

func (e *bcdEncoder) Encode(src []byte) ([]byte, error) {
// Encode returns packed data and the original length in digits
func (e *bcdEncoder) Encode(src []byte) ([]byte, int, error) {
length := len(src)
if len(src)%2 != 0 {
src = append([]byte("0"), src...)
}
Expand All @@ -23,12 +25,13 @@ func (e *bcdEncoder) Encode(src []byte) ([]byte, error) {
dst := make([]byte, bcd.EncodedLen(len(src)))
n, err := enc.Encode(dst, src)
if err != nil {
return nil, utils.NewSafeError(err, "failed to perform BCD encoding")
return nil, 0, utils.NewSafeError(err, "failed to perform BCD encoding")
}

return dst[:n], nil
return dst[:n], length, nil
}

// Decode returns bcd unpacked data and number of digits decoded
func (e *bcdEncoder) Decode(src []byte, length int) ([]byte, int, error) {
// length should be positive
if length < 0 {
Expand Down
7 changes: 4 additions & 3 deletions encoding/bcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,17 @@ func TestBCD(t *testing.T) {
})

t.Run("Encode", func(t *testing.T) {
res, err := BCD.Encode([]byte("0110"))
res, _, err := BCD.Encode([]byte("0110"))
require.NoError(t, err)
require.Equal(t, []byte{0x01, 0x10}, res)

// right justified by default
res, err = BCD.Encode([]byte("123"))
res, length, err := BCD.Encode([]byte("123"))
require.NoError(t, err)
require.Equal(t, []byte{0x01, 0x23}, res)
require.Equal(t, 3, length)

_, err = BCD.Encode([]byte("abc"))
_, _, err = BCD.Encode([]byte("abc"))
require.Error(t, err)
require.EqualError(t, err, "failed to perform BCD encoding")
require.ErrorIs(t, err, bcd.ErrBadInput)
Expand Down
5 changes: 2 additions & 3 deletions encoding/bertlv.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ type berTLVEncoderTag struct{}

// Encode converts ASCII Hex-digits into a byte slice e.g. []byte("AABBCC")
// would be converted into []byte{0xAA, 0xBB, 0xCC}
func (berTLVEncoderTag) Encode(data []byte) ([]byte, error) {
out, err := ASCIIHexToBytes.Encode(data)
return out, err
func (berTLVEncoderTag) Encode(data []byte) ([]byte, int, error) {
return ASCIIHexToBytes.Encode(data)
}

// Decode converts hexadecimal TLV bytes into their ASCII representation according
Expand Down
2 changes: 1 addition & 1 deletion encoding/bertlv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func TestBerTLVTag(t *testing.T) {

for _, tt := range tests {
t.Run(tt.desc+"_Encode", func(t *testing.T) {
hexTag, err := BerTLVTag.Encode(tt.asciiTag)
hexTag, _, err := BerTLVTag.Encode(tt.asciiTag)
require.NoError(t, err)
require.Equal(t, tt.hexTag, hexTag)
})
Expand Down
4 changes: 2 additions & 2 deletions encoding/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ var (

type binaryEncoder struct{}

func (e binaryEncoder) Encode(data []byte) ([]byte, error) {
func (e binaryEncoder) Encode(data []byte) ([]byte, int, error) {
out := append([]byte(nil), data...)

return out, nil
return out, len(out), nil
}

func (e binaryEncoder) Decode(data []byte, length int) ([]byte, int, error) {
Expand Down
4 changes: 2 additions & 2 deletions encoding/ebcdic.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ var (

type ebcdicEncoder struct{}

func (e *ebcdicEncoder) Encode(src []byte) ([]byte, error) {
func (e *ebcdicEncoder) Encode(src []byte) ([]byte, int, error) {
var dst []byte
for _, v := range src {
dst = append(dst, asciiToEbcdic[v])
}
return dst, nil
return dst, len(dst), nil
}

func (e *ebcdicEncoder) Decode(src []byte, length int) ([]byte, int, error) {
Expand Down
6 changes: 3 additions & 3 deletions encoding/ebcdic1047.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ type ebcdic1047Encoder struct {
decoder *xencoding.Decoder
}

func (e ebcdic1047Encoder) Encode(data []byte) ([]byte, error) {
func (e ebcdic1047Encoder) Encode(data []byte) ([]byte, int, error) {
bytes, err := e.encoder.Bytes(data)
if err != nil {
return nil, utils.NewSafeError(err, "failed to encode EBCDIC")
return nil, 0, utils.NewSafeError(err, "failed to encode EBCDIC")
}
return bytes, nil
return bytes, len(bytes), nil
}

func (e ebcdic1047Encoder) Decode(data []byte, length int) ([]byte, int, error) {
Expand Down
4 changes: 2 additions & 2 deletions encoding/ebcdic1047_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ var knownEncodings = []struct {
func TestEBCDIC1047SingleCharacterEncode(t *testing.T) {
t.Parallel()
for character, expectedEncoding := range ebcdic1047CharacterEncodings {
encoding, err := EBCDIC1047.Encode([]byte(character))
encoding, _, err := EBCDIC1047.Encode([]byte(character))
require.NoError(t, err)
require.Len(t, encoding, 1)
require.Equal(t, expectedEncoding, encoding[0])
Expand All @@ -240,7 +240,7 @@ func TestEBCDIC1047SingleCharacterDecode(t *testing.T) {
func TestEBCDIC1047Encode(t *testing.T) {
t.Parallel()
for _, testCase := range knownEncodings {
encoding, err := EBCDIC1047.Encode([]byte(testCase.Phrase))
encoding, _, err := EBCDIC1047.Encode([]byte(testCase.Phrase))
require.NoError(t, err)
require.Equal(t, testCase.Encoding, encoding)
}
Expand Down
2 changes: 1 addition & 1 deletion encoding/ebcdic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestEBCDIC(t *testing.T) {
})

t.Run("Encode", func(t *testing.T) {
res, err := EBCDIC.Encode([]byte{0x12, 0x94})
res, _, err := EBCDIC.Encode([]byte{0x12, 0x94})

require.NoError(t, err)
require.Equal(t, []byte{0x12, 0x34}, res)
Expand Down
6 changes: 4 additions & 2 deletions encoding/encoder.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package encoding

type Encoder interface {
Encode([]byte) ([]byte, error)
// Returns data decoded into ASCII (or bytes), how many bytes were read, error
// Encode packs the data and returns the length in the encoding's representation.
// the length is usually the number of bytes, but in bcd the number of encoded digits.
Encode([]byte) (packed []byte, length int, err error)
// Decode returns data decoded into ASCII (or bytes), how many bytes were read, error
Decode([]byte, int) (data []byte, read int, err error)
}
10 changes: 5 additions & 5 deletions encoding/hex.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ type hexToASCIIEncoder struct{}
// Encode converts bytes into their ASCII representation. On success, the
// ASCII representation bytes are returned e.g. []byte{0x5F, 0x2A} would be
// converted to []byte("5F2A")
func (e hexToASCIIEncoder) Encode(data []byte) ([]byte, error) {
func (e hexToASCIIEncoder) Encode(data []byte) ([]byte, int, error) {
out := make([]byte, hex.EncodedLen(len(data)))
hex.Encode(out, data)

str := string(out)
str = strings.ToUpper(str)

return []byte(str), nil
return []byte(str), len(str), nil
}

// Decodes ASCII hex and returns bytes
Expand Down Expand Up @@ -64,15 +64,15 @@ type asciiToHexEncoder struct{}

// Encode converts ASCII Hex-digits into a byte slice e.g. []byte("AABBCC")
// would be converted into []byte{0xAA, 0xBB, 0xCC}
func (e asciiToHexEncoder) Encode(data []byte) ([]byte, error) {
func (e asciiToHexEncoder) Encode(data []byte) ([]byte, int, error) {
out := make([]byte, hex.DecodedLen(len(data)))

_, err := hex.Decode(out, data)
if err != nil {
return nil, utils.NewSafeError(err, "failed to perform hex decoding")
return nil, 0, utils.NewSafeError(err, "failed to perform hex decoding")
}

return out, nil
return out, len(out), nil
}

// Decode converts bytes into their ASCII representation.
Expand Down
6 changes: 3 additions & 3 deletions encoding/hex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestHexToASCIIEncoder(t *testing.T) {
require.Error(t, err)
require.EqualError(t, err, "failed to perform hex decoding")

got, err = enc.Encode([]byte{0xAA, 0xBB, 0xCC})
got, _, err = enc.Encode([]byte{0xAA, 0xBB, 0xCC})
require.NoError(t, err)
require.Equal(t, []byte("AABBCC"), got)
}
Expand All @@ -35,11 +35,11 @@ func TestASCIIToHexEncoder(t *testing.T) {
require.Equal(t, []byte("AABBCC"), got)
require.Equal(t, 3, read)

got, err = enc.Encode([]byte("aabbcc"))
got, _, err = enc.Encode([]byte("aabbcc"))
require.NoError(t, err)
require.Equal(t, []byte{0xAA, 0xBB, 0xCC}, got)

_, err = enc.Encode([]byte("nothex"))
_, _, err = enc.Encode([]byte("nothex"))
require.Error(t, err)
require.EqualError(t, err, "failed to perform hex decoding")
}
Expand Down
7 changes: 4 additions & 3 deletions encoding/lbcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ var (

type lBCDEncoder struct{}

func (e *lBCDEncoder) Encode(src []byte) ([]byte, error) {
func (e *lBCDEncoder) Encode(src []byte) ([]byte, int, error) {
length := len(src)
if len(src)%2 != 0 {
src = append(src, []byte("0")...)
}
Expand All @@ -23,10 +24,10 @@ func (e *lBCDEncoder) Encode(src []byte) ([]byte, error) {
dst := make([]byte, bcd.EncodedLen(len(src)))
n, err := enc.Encode(dst, src)
if err != nil {
return nil, utils.NewSafeError(err, "failed to perform BCD encoding")
return nil, 0, utils.NewSafeError(err, "failed to perform BCD encoding")
}

return dst[:n], nil
return dst[:n], length, nil
}

func (e *lBCDEncoder) Decode(src []byte, length int) ([]byte, int, error) {
Expand Down
5 changes: 3 additions & 2 deletions encoding/lbcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ func TestLBCD(t *testing.T) {
})

t.Run("Encode", func(t *testing.T) {
res, err := LBCD.Encode([]byte("123"))
res, encLength, err := LBCD.Encode([]byte("123"))
require.NoError(t, err)
require.Equal(t, []byte{0x12, 0x30}, res)
require.Equal(t, 3, encLength)

_, err = LBCD.Encode([]byte("abc"))
_, _, err = LBCD.Encode([]byte("abc"))
require.Error(t, err)
require.EqualError(t, err, "failed to perform BCD encoding")
require.ErrorIs(t, err, bcd.ErrBadInput)
Expand Down
6 changes: 3 additions & 3 deletions field/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ func (f *Binary) Pack() ([]byte, error) {
data = f.spec.Pad.Pad(data, f.spec.Length)
}

packed, err := f.spec.Enc.Encode(data)
packed, encLength, err := f.spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, len(packed))
packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, encLength)
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}
Expand Down Expand Up @@ -169,7 +169,7 @@ func (f *Binary) UnmarshalJSON(b []byte) error {
return utils.NewSafeError(err, "failed to JSON unmarshal bytes to string")
}

hex, err := encoding.ASCIIHexToBytes.Encode([]byte(v))
hex, _, err := encoding.ASCIIHexToBytes.Encode([]byte(v))
if err != nil {
return utils.NewSafeError(err, "failed to convert ASCII Hex string to bytes")
}
Expand Down
2 changes: 1 addition & 1 deletion field/bitmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (f *Bitmap) String() (string, error) {
}

func (f *Bitmap) Pack() ([]byte, error) {
packed, err := f.spec.Enc.Encode(f.data)
packed, _, err := f.spec.Enc.Encode(f.data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}
Expand Down
7 changes: 4 additions & 3 deletions field/composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/moov-io/iso8583/encoding"
"github.com/moov-io/iso8583/prefix"
"reflect"
"regexp"

"github.com/moov-io/iso8583/encoding"
"github.com/moov-io/iso8583/prefix"

"github.com/moov-io/iso8583/padding"
"github.com/moov-io/iso8583/sort"
"github.com/moov-io/iso8583/utils"
Expand Down Expand Up @@ -363,7 +364,7 @@ func (f *Composite) pack() ([]byte, error) {
if f.spec.Tag.Pad != nil {
tagBytes = f.spec.Tag.Pad.Pad(tagBytes, f.spec.Tag.Length)
}
tagBytes, err := f.spec.Tag.Enc.Encode(tagBytes)
tagBytes, _, err := f.spec.Tag.Enc.Encode(tagBytes)
if err != nil {
return nil, fmt.Errorf("failed to convert subfield Tag \"%v\" to int", tagBytes)
}
Expand Down
4 changes: 2 additions & 2 deletions field/numeric.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,12 @@ func (f *Numeric) Pack() ([]byte, error) {
data = f.spec.Pad.Pad(data, f.spec.Length)
}

packed, err := f.spec.Enc.Encode(data)
packed, encLength, err := f.spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, len(packed))
packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, encLength)
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions field/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ func (f *String) Pack() ([]byte, error) {
data = f.spec.Pad.Pad(data, f.spec.Length)
}

packed, err := f.spec.Enc.Encode(data)
packed, encodedLength, err := f.spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, len(packed))
packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, encodedLength)
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions field/track1.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ func (f *Track1) Pack() ([]byte, error) {
data = f.spec.Pad.Pad(data, f.spec.Length)
}

packed, err := f.spec.Enc.Encode(data)
packed, encLength, err := f.spec.Enc.Encode(data)
if err != nil {
return nil, fmt.Errorf("failed to encode content: %w", err)
}

packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, len(packed))
packedLength, err := f.spec.Pref.EncodeLength(f.spec.Length, encLength)
if err != nil {
return nil, fmt.Errorf("failed to encode length: %w", err)
}
Expand Down
Loading