From 63e3bc4355d9b04b25f26d19b8e2b2faf0ffbbcf Mon Sep 17 00:00:00 2001 From: Charles Iliya Krempeaux Date: Sat, 7 Oct 2023 00:54:15 -0700 Subject: [PATCH] initial commits --- errors.go | 1 + pctencoded.go | 87 +++++++ pctencoded_readpctencodedbyte_test.go | 345 ++++++++++++++++++++++++++ 3 files changed, 433 insertions(+) create mode 100644 pctencoded_readpctencodedbyte_test.go diff --git a/errors.go b/errors.go index 868e44b..6449fbf 100644 --- a/errors.go +++ b/errors.go @@ -5,5 +5,6 @@ import ( ) const ( + errNilReader = erorr.Error("rfc3986: nil reader") errNilWriter = erorr.Error("rfc3986: nil writer") ) diff --git a/pctencoded.go b/pctencoded.go index bad7eae..1fc529b 100644 --- a/pctencoded.go +++ b/pctencoded.go @@ -2,8 +2,95 @@ package rfc3986 import ( "io" + + "sourcecode.social/reiver/go-erorr" ) +func ReadPctEncodedByte(reader io.Reader) (byte, error) { + if nil == reader { + return 0, errNilReader + } + + var buffer [1]byte + var p []byte = buffer[:] + + { + const expected byte = '%' + + n, err := reader.Read(p) + if nil != err { + return 0, erorr.Errorf("rfc3986: could not read the 1st byte in pct-encoded string because: %w", err) + } + if 1 != n { + return 0, erorr.Errorf("rfc3986: problem reading the 1st byte in pct-encoded string — expected to have read 1 byte but actually read %d bytes.", n) + } + + actual := buffer[0] + + if expected != actual { + return 0, erorr.Errorf("rfc3986:the 1st byte in pct-encoded string is not a percent-sign (%U) (%q) is actually %U (%q)", expected, expected, actual, actual) + } + } + + var result byte = 0 + + { + n, err := reader.Read(p) + if nil != err { + return 0, erorr.Errorf("rfc3986: could not read the 2nd byte in pct-encoded string because: %w", err) + } + if 1 != n { + return 0, erorr.Errorf("rfc3986: problem reading the 2nd byte in pct-encoded string — expected to have read 1 byte but actually read %d bytes.", n) + } + + b0 := buffer[0] + + switch { + case '0' <= b0 && b0 <= '9': + b0 -= '0' + case 'A' <= b0 && b0 <= 'F': + b0 -= 'A' + b0 += 10 + case 'a' <= b0 && b0 <= 'f': + b0 -= 'a' + b0 += 10 + default: + return 0, erorr.Errorf("rfc3986: the 2nd byte in the pct-encoded string is not an IETF RFC-2234 'HEXDIG'") + } + + result |= (b0 << 4) + } + + { + n, err := reader.Read(p) + if nil != err { + return 0, erorr.Errorf("rfc3986: could not read the 3rd byte in pct-encoded string because: %w", err) + } + if 1 != n { + return 0, erorr.Errorf("rfc3986: problem reading the 3rd byte in pct-encoded string — expected to have read 1 byte but actually read %d bytes.", n) + } + + b0 := buffer[0] + + switch { + case '0' <= b0 && b0 <= '9': + b0 -= '0' + case 'A' <= b0 && b0 <= 'F': + b0 -= 'A' + b0 += 10 + case 'a' <= b0 && b0 <= 'f': + b0 -= 'a' + b0 += 10 + default: + return 0, erorr.Errorf("rfc3986: the 2nd byte in the pct-encoded string is not an IETF RFC-2234 'HEXDIG'") + } + + result |= b0 + } + + return result, nil +} + func WritePctEncodedByte(writer io.Writer, b byte) error { if nil == writer { return errNilWriter diff --git a/pctencoded_readpctencodedbyte_test.go b/pctencoded_readpctencodedbyte_test.go new file mode 100644 index 0000000..108bcce --- /dev/null +++ b/pctencoded_readpctencodedbyte_test.go @@ -0,0 +1,345 @@ +package rfc3986_test + +import ( + "testing" + + "io" + "strings" + + "sourcecode.social/reiver/go-rfc3986" +) + +func TestReadPctEncodedByte(t *testing.T) { + + tests := []struct{ + Value string + Expected byte + }{ + { + Value: "%00", + Expected: 0, + }, + { + Value: "%01", + Expected: 1, + }, + { + Value: "%02", + Expected: 2, + }, + { + Value: "%03", + Expected: 3, + }, + { + Value: "%04", + Expected: 4, + }, + { + Value: "%05", + Expected: 5, + }, + { + Value: "%06", + Expected: 6, + }, + { + Value: "%07", + Expected: 7, + }, + { + Value: "%08", + Expected: 8, + }, + { + Value: "%09", + Expected: 9, + }, + { + Value: "%0A", + Expected: 10, + }, + { + Value: "%0B", + Expected: 11, + }, + { + Value: "%0C", + Expected: 12, + }, + { + Value: "%0D", + Expected: 13, + }, + { + Value: "%0E", + Expected: 14, + }, + { + Value: "%0F", + Expected: 15, + }, + + + + { + Value: "%0a", + Expected: 10, + }, + { + Value: "%0b", + Expected: 11, + }, + { + Value: "%0c", + Expected: 12, + }, + { + Value: "%0d", + Expected: 13, + }, + { + Value: "%0e", + Expected: 14, + }, + { + Value: "%0f", + Expected: 15, + }, + + + + { + Value: "%10", + Expected: 16, + }, + { + Value: "%11", + Expected: 17, + }, + { + Value: "%12", + Expected: 18, + }, + { + Value: "%13", + Expected: 19, + }, + { + Value: "%14", + Expected: 20, + }, + { + Value: "%15", + Expected: 21, + }, + { + Value: "%16", + Expected: 22, + }, + { + Value: "%17", + Expected: 23, + }, + { + Value: "%18", + Expected: 24, + }, + { + Value: "%19", + Expected: 25, + }, + { + Value: "%1A", + Expected: 26, + }, + { + Value: "%1B", + Expected: 27, + }, + { + Value: "%1C", + Expected: 28, + }, + { + Value: "%1D", + Expected: 29, + }, + { + Value: "%1E", + Expected: 30, + }, + { + Value: "%1F", + Expected: 31, + }, + + + + { + Value: "%1a", + Expected: 26, + }, + { + Value: "%1b", + Expected: 27, + }, + { + Value: "%1c", + Expected: 28, + }, + { + Value: "%1d", + Expected: 29, + }, + { + Value: "%1e", + Expected: 30, + }, + { + Value: "%1f", + Expected: 31, + }, + + + + { + Value: "%20F", + Expected: 32, + }, + + + + { + Value: "%FA", + Expected: 250, + }, + { + Value: "%FB", + Expected: 251, + }, + { + Value: "%FC", + Expected: 252, + }, + { + Value: "%FD", + Expected: 253, + }, + { + Value: "%FE", + Expected: 254, + }, + { + Value: "%FF", + Expected: 255, + }, + + + + { + Value: "%Fa", + Expected: 250, + }, + { + Value: "%Fb", + Expected: 251, + }, + { + Value: "%Fc", + Expected: 252, + }, + { + Value: "%Fd", + Expected: 253, + }, + { + Value: "%Fe", + Expected: 254, + }, + { + Value: "%Ff", + Expected: 255, + }, + + + + { + Value: "%fA", + Expected: 250, + }, + { + Value: "%fB", + Expected: 251, + }, + { + Value: "%fC", + Expected: 252, + }, + { + Value: "%fD", + Expected: 253, + }, + { + Value: "%fE", + Expected: 254, + }, + { + Value: "%fF", + Expected: 255, + }, + + + + { + Value: "%fa", + Expected: 250, + }, + { + Value: "%fb", + Expected: 251, + }, + { + Value: "%fc", + Expected: 252, + }, + { + Value: "%fd", + Expected: 253, + }, + { + Value: "%fe", + Expected: 254, + }, + { + Value: "%ff", + Expected: 255, + }, + } + + for testNumber, test := range tests { + + var reader io.Reader = strings.NewReader(test.Value) + + actual, err := rfc3986.ReadPctEncodedByte(reader) + if nil != err { + t.Errorf("For test #%d, did not expect an error but actually got one." , testNumber) + t.Logf("ERROR: (%T) %s", err, err) + t.Logf("VALUE: %q", test.Value) + t.Logf("EXPECTED: %d (0x%X)", test.Expected, test.Expected) + continue + } + + { + expected := test.Expected + + if expected != actual { + t.Errorf("For test #%d, the actual byte returned is not what was expected.", testNumber) + t.Logf("EXPECTED: %d (0x%X)", expected, expected) + t.Logf("ACTUAL: %d (0x%X)", actual, actual) + t.Logf("VALUE: %q", test.Value) + continue + } + } + } +}