diff options
Diffstat (limited to 'src/pkg/encoding')
-rw-r--r-- | src/pkg/encoding/base64/base64.go | 14 | ||||
-rw-r--r-- | src/pkg/encoding/base64/base64_test.go | 9 | ||||
-rw-r--r-- | src/pkg/encoding/binary/binary.go | 102 | ||||
-rw-r--r-- | src/pkg/encoding/binary/binary_test.go | 73 | ||||
-rw-r--r-- | src/pkg/encoding/git85/git.go | 2 | ||||
-rw-r--r-- | src/pkg/encoding/hex/hex.go | 116 | ||||
-rw-r--r-- | src/pkg/encoding/hex/hex_test.go | 43 | ||||
-rw-r--r-- | src/pkg/encoding/line/Makefile | 11 | ||||
-rw-r--r-- | src/pkg/encoding/line/line.go | 115 | ||||
-rw-r--r-- | src/pkg/encoding/line/line_test.go | 133 | ||||
-rw-r--r-- | src/pkg/encoding/pem/pem.go | 2 |
11 files changed, 356 insertions, 264 deletions
diff --git a/src/pkg/encoding/base64/base64.go b/src/pkg/encoding/base64/base64.go index 496129798..c6b2a13e4 100644 --- a/src/pkg/encoding/base64/base64.go +++ b/src/pkg/encoding/base64/base64.go @@ -106,6 +106,13 @@ func (enc *Encoding) Encode(dst, src []byte) { } } +// EncodeToString returns the base64 encoding of src. +func (enc *Encoding) EncodeToString(src []byte) string { + buf := make([]byte, enc.EncodedLen(len(src))) + enc.Encode(buf, src) + return string(buf) +} + type encoder struct { err os.Error enc *Encoding @@ -260,6 +267,13 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) { return } +// DecodeString returns the bytes represented by the base64 string s. +func (enc *Encoding) DecodeString(s string) ([]byte, os.Error) { + dbuf := make([]byte, enc.DecodedLen(len(s))) + n, err := enc.Decode(dbuf, []byte(s)) + return dbuf[:n], err +} + type decoder struct { err os.Error enc *Encoding diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go index de41e704b..c163dae84 100644 --- a/src/pkg/encoding/base64/base64_test.go +++ b/src/pkg/encoding/base64/base64_test.go @@ -56,9 +56,8 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool { func TestEncode(t *testing.T) { for _, p := range pairs { - buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded))) - StdEncoding.Encode(buf, []byte(p.decoded)) - testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded) + got := StdEncoding.EncodeToString([]byte(p.decoded)) + testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded) } } @@ -102,6 +101,10 @@ func TestDecode(t *testing.T) { testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '=')) } testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded) + + dbuf, err = StdEncoding.DecodeString(p.encoded) + testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, os.Error(nil)) + testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded) } } diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go index a01d0e024..8e55cb23b 100644 --- a/src/pkg/encoding/binary/binary.go +++ b/src/pkg/encoding/binary/binary.go @@ -125,6 +125,35 @@ func (bigEndian) GoString() string { return "binary.BigEndian" } // Bytes read from r are decoded using the specified byte order // and written to successive fields of the data. func Read(r io.Reader, order ByteOrder, data interface{}) os.Error { + // Fast path for basic types. + if n := intDestSize(data); n != 0 { + var b [8]byte + bs := b[:n] + if _, err := io.ReadFull(r, bs); err != nil { + return err + } + switch v := data.(type) { + case *int8: + *v = int8(b[0]) + case *uint8: + *v = b[0] + case *int16: + *v = int16(order.Uint16(bs)) + case *uint16: + *v = order.Uint16(bs) + case *int32: + *v = int32(order.Uint32(bs)) + case *uint32: + *v = order.Uint32(bs) + case *int64: + *v = int64(order.Uint64(bs)) + case *uint64: + *v = order.Uint64(bs) + } + return nil + } + + // Fallback to reflect-based. var v reflect.Value switch d := reflect.ValueOf(data); d.Kind() { case reflect.Ptr: @@ -155,6 +184,63 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error { // Bytes written to w are encoded using the specified byte order // and read from successive fields of the data. func Write(w io.Writer, order ByteOrder, data interface{}) os.Error { + // Fast path for basic types. + var b [8]byte + var bs []byte + switch v := data.(type) { + case *int8: + bs = b[:1] + b[0] = byte(*v) + case int8: + bs = b[:1] + b[0] = byte(v) + case *uint8: + bs = b[:1] + b[0] = *v + case uint8: + bs = b[:1] + b[0] = byte(v) + case *int16: + bs = b[:2] + order.PutUint16(bs, uint16(*v)) + case int16: + bs = b[:2] + order.PutUint16(bs, uint16(v)) + case *uint16: + bs = b[:2] + order.PutUint16(bs, *v) + case uint16: + bs = b[:2] + order.PutUint16(bs, v) + case *int32: + bs = b[:4] + order.PutUint32(bs, uint32(*v)) + case int32: + bs = b[:4] + order.PutUint32(bs, uint32(v)) + case *uint32: + bs = b[:4] + order.PutUint32(bs, *v) + case uint32: + bs = b[:4] + order.PutUint32(bs, v) + case *int64: + bs = b[:8] + order.PutUint64(bs, uint64(*v)) + case int64: + bs = b[:8] + order.PutUint64(bs, uint64(v)) + case *uint64: + bs = b[:8] + order.PutUint64(bs, *v) + case uint64: + bs = b[:8] + order.PutUint64(bs, v) + } + if bs != nil { + _, err := w.Write(bs) + return err + } v := reflect.Indirect(reflect.ValueOf(data)) size := TotalSize(v) if size < 0 { @@ -394,3 +480,19 @@ func (e *encoder) value(v reflect.Value) { } } } + +// intDestSize returns the size of the integer that ptrType points to, +// or 0 if the type is not supported. +func intDestSize(ptrType interface{}) int { + switch ptrType.(type) { + case *int8, *uint8: + return 1 + case *int16, *uint16: + return 2 + case *int32, *uint32: + return 4 + case *int64, *uint64: + return 8 + } + return 0 +} diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go index 7857c68d3..b266996f6 100644 --- a/src/pkg/encoding/binary/binary_test.go +++ b/src/pkg/encoding/binary/binary_test.go @@ -5,6 +5,7 @@ package binary import ( + "io" "os" "bytes" "math" @@ -160,3 +161,75 @@ func TestWriteT(t *testing.T) { } } } + +type byteSliceReader struct { + remain []byte +} + +func (br *byteSliceReader) Read(p []byte) (int, os.Error) { + n := copy(p, br.remain) + br.remain = br.remain[n:] + return n, nil +} + +func BenchmarkRead(b *testing.B) { + var ls Struct + bsr := &byteSliceReader{} + var r io.Reader = bsr + + for i := 0; i < b.N; i++ { + bsr.remain = big + Read(r, BigEndian, &ls.Int8) + Read(r, BigEndian, &ls.Int16) + Read(r, BigEndian, &ls.Int32) + Read(r, BigEndian, &ls.Int64) + Read(r, BigEndian, &ls.Uint8) + Read(r, BigEndian, &ls.Uint16) + Read(r, BigEndian, &ls.Uint32) + Read(r, BigEndian, &ls.Uint64) + } + + want := s + want.Float32 = 0 + want.Float64 = 0 + want.Complex64 = 0 + want.Complex128 = 0 + for i := range want.Array { + want.Array[i] = 0 + } + if !reflect.DeepEqual(ls, want) { + panic("no match") + } +} + +func BenchmarkWrite(b *testing.B) { + buf := new(bytes.Buffer) + var w io.Writer = buf + + for i := 0; i < b.N; i++ { + buf.Reset() + Write(w, BigEndian, &s.Int8) + Write(w, BigEndian, &s.Int16) + Write(w, BigEndian, &s.Int32) + Write(w, BigEndian, &s.Int64) + Write(w, BigEndian, &s.Uint8) + Write(w, BigEndian, &s.Uint16) + Write(w, BigEndian, &s.Uint32) + Write(w, BigEndian, &s.Uint64) + Write(w, BigEndian, s.Int8) + Write(w, BigEndian, s.Int16) + Write(w, BigEndian, s.Int32) + Write(w, BigEndian, s.Int64) + Write(w, BigEndian, s.Uint8) + Write(w, BigEndian, s.Uint16) + Write(w, BigEndian, s.Uint32) + Write(w, BigEndian, s.Uint64) + } + + if !bytes.Equal(buf.Bytes()[:30], big[:30]) { + panic("first half doesn't match") + } + if !bytes.Equal(buf.Bytes()[30:], big[:30]) { + panic("second half doesn't match") + } +} diff --git a/src/pkg/encoding/git85/git.go b/src/pkg/encoding/git85/git.go index 09a45cd3c..6bb74f46c 100644 --- a/src/pkg/encoding/git85/git.go +++ b/src/pkg/encoding/git85/git.go @@ -273,5 +273,5 @@ func (d *decoder) Read(p []byte) (n int, err os.Error) { d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf]) d.off += int64(nl + 1) } - panic("unreacahable") + panic("unreachable") } diff --git a/src/pkg/encoding/hex/hex.go b/src/pkg/encoding/hex/hex.go index 891de1861..47cdedd60 100644 --- a/src/pkg/encoding/hex/hex.go +++ b/src/pkg/encoding/hex/hex.go @@ -6,6 +6,8 @@ package hex import ( + "bytes" + "io" "os" "strconv" ) @@ -99,3 +101,117 @@ func DecodeString(s string) ([]byte, os.Error) { } return dst, nil } + +// Dump returns a string that contains a hex dump of the given data. The format +// of the hex dump matches the output of `hexdump -C` on the command line. +func Dump(data []byte) string { + buf := bytes.NewBuffer(nil) + dumper := Dumper(buf) + dumper.Write(data) + dumper.Close() + return string(buf.Bytes()) +} + +// Dumper returns a WriteCloser that writes a hex dump of all written data to +// w. The format of the dump matches the output of `hexdump -C` on the command +// line. +func Dumper(w io.Writer) io.WriteCloser { + return &dumper{w: w} +} + +type dumper struct { + w io.Writer + rightChars [18]byte + buf [14]byte + used int // number of bytes in the current line + n uint // number of bytes, total +} + +func toChar(b byte) byte { + if b < 32 || b > 126 { + return '.' + } + return b +} + +func (h *dumper) Write(data []byte) (n int, err os.Error) { + // Output lines look like: + // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=| + // ^ offset ^ extra space ^ ASCII of line. + for i := range data { + if h.used == 0 { + // At the beginning of a line we print the current + // offset in hex. + h.buf[0] = byte(h.n >> 24) + h.buf[1] = byte(h.n >> 16) + h.buf[2] = byte(h.n >> 8) + h.buf[3] = byte(h.n) + Encode(h.buf[4:], h.buf[:4]) + h.buf[12] = ' ' + h.buf[13] = ' ' + _, err = h.w.Write(h.buf[4:]) + } + Encode(h.buf[:], data[i:i+1]) + h.buf[2] = ' ' + l := 3 + if h.used == 7 { + // There's an additional space after the 8th byte. + h.buf[3] = ' ' + l = 4 + } else if h.used == 15 { + // At the end of the line there's an extra space and + // the bar for the right column. + h.buf[3] = ' ' + h.buf[4] = '|' + l = 5 + } + _, err = h.w.Write(h.buf[:l]) + if err != nil { + return + } + n++ + h.rightChars[h.used] = toChar(data[i]) + h.used++ + h.n++ + if h.used == 16 { + h.rightChars[16] = '|' + h.rightChars[17] = '\n' + _, err = h.w.Write(h.rightChars[:]) + if err != nil { + return + } + h.used = 0 + } + } + return +} + +func (h *dumper) Close() (err os.Error) { + // See the comments in Write() for the details of this format. + if h.used == 0 { + return + } + h.buf[0] = ' ' + h.buf[1] = ' ' + h.buf[2] = ' ' + h.buf[3] = ' ' + h.buf[4] = '|' + nBytes := h.used + for h.used < 16 { + l := 3 + if h.used == 7 { + l = 4 + } else if h.used == 15 { + l = 5 + } + _, err = h.w.Write(h.buf[:l]) + if err != nil { + return + } + h.used++ + } + h.rightChars[nBytes] = '|' + h.rightChars[nBytes+1] = '\n' + _, err = h.w.Write(h.rightChars[:nBytes+2]) + return +} diff --git a/src/pkg/encoding/hex/hex_test.go b/src/pkg/encoding/hex/hex_test.go index a14c9d4f4..8e1838e51 100644 --- a/src/pkg/encoding/hex/hex_test.go +++ b/src/pkg/encoding/hex/hex_test.go @@ -147,3 +147,46 @@ func TestDecodeString(t *testing.T) { } } } + +func TestDumper(t *testing.T) { + var in [40]byte + for i := range in { + in[i] = byte(i + 30) + } + + for stride := 1; stride < len(in); stride++ { + out := bytes.NewBuffer(nil) + dumper := Dumper(out) + done := 0 + for done < len(in) { + todo := done + stride + if todo > len(in) { + todo = len(in) + } + dumper.Write(in[done:todo]) + done = todo + } + + dumper.Close() + if !bytes.Equal(out.Bytes(), expectedHexDump) { + t.Errorf("stride: %d failed. got:\n%s\nwant:\n%s", stride, out.Bytes(), expectedHexDump) + } + } +} + +func TestDump(t *testing.T) { + var in [40]byte + for i := range in { + in[i] = byte(i + 30) + } + + out := []byte(Dump(in[:])) + if !bytes.Equal(out, expectedHexDump) { + t.Errorf("got:\n%s\nwant:\n%s", out, expectedHexDump) + } +} + +var expectedHexDump = []byte(`00000000 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d |.. !"#$%&'()*+,-| +00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=| +00000020 3e 3f 40 41 42 43 44 45 |>?@ABCDE| +`) diff --git a/src/pkg/encoding/line/Makefile b/src/pkg/encoding/line/Makefile deleted file mode 100644 index 1af355c27..000000000 --- a/src/pkg/encoding/line/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2010 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../../Make.inc - -TARG=encoding/line -GOFILES=\ - line.go\ - -include ../../../Make.pkg diff --git a/src/pkg/encoding/line/line.go b/src/pkg/encoding/line/line.go deleted file mode 100644 index 123962b1f..000000000 --- a/src/pkg/encoding/line/line.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package line implements a Reader that reads lines delimited by '\n' or -// ' \r\n'. -package line - -import ( - "io" - "os" -) - -// Reader reads lines, delimited by '\n' or \r\n', from an io.Reader. -type Reader struct { - buf []byte - consumed int - in io.Reader - err os.Error -} - -// NewReader returns a new Reader that will read successive -// lines from the input Reader. -func NewReader(input io.Reader, maxLineLength int) *Reader { - return &Reader{ - buf: make([]byte, 0, maxLineLength), - consumed: 0, - in: input, - } -} - -// Read reads from any buffered data past the last line read, or from the underlying -// io.Reader if the buffer is empty. -func (l *Reader) Read(p []byte) (n int, err os.Error) { - l.removeConsumedFromBuffer() - if len(l.buf) > 0 { - n = copy(p, l.buf) - l.consumed += n - return - } - return l.in.Read(p) -} - -func (l *Reader) removeConsumedFromBuffer() { - if l.consumed > 0 { - n := copy(l.buf, l.buf[l.consumed:]) - l.buf = l.buf[:n] - l.consumed = 0 - } -} - -// ReadLine tries to return a single line, not including the end-of-line bytes. -// If the line was found to be longer than the maximum length then isPrefix is -// set and the beginning of the line is returned. The rest of the line will be -// returned from future calls. isPrefix will be false when returning the last -// fragment of the line. The returned buffer points into the internal state of -// the Reader and is only valid until the next call to ReadLine. ReadLine -// either returns a non-nil line or it returns an error, never both. -func (l *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) { - l.removeConsumedFromBuffer() - - if len(l.buf) == 0 && l.err != nil { - err = l.err - return - } - - scannedTo := 0 - - for { - i := scannedTo - for ; i < len(l.buf); i++ { - if l.buf[i] == '\r' && len(l.buf) > i+1 && l.buf[i+1] == '\n' { - line = l.buf[:i] - l.consumed = i + 2 - return - } else if l.buf[i] == '\n' { - line = l.buf[:i] - l.consumed = i + 1 - return - } - } - - if i == cap(l.buf) { - line = l.buf[:i] - l.consumed = i - isPrefix = true - return - } - - if l.err != nil { - line = l.buf - l.consumed = i - return - } - - // We don't want to rescan the input that we just scanned. - // However, we need to back up one byte because the last byte - // could have been a '\r' and we do need to rescan that. - scannedTo = i - if scannedTo > 0 { - scannedTo-- - } - oldLen := len(l.buf) - l.buf = l.buf[:cap(l.buf)] - n, readErr := l.in.Read(l.buf[oldLen:]) - l.buf = l.buf[:oldLen+n] - if readErr != nil { - l.err = readErr - if len(l.buf) == 0 { - return nil, false, readErr - } - } - } - panic("unreachable") -} diff --git a/src/pkg/encoding/line/line_test.go b/src/pkg/encoding/line/line_test.go deleted file mode 100644 index ff3d51669..000000000 --- a/src/pkg/encoding/line/line_test.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package line - -import ( - "bytes" - "io" - "io/ioutil" - "os" - "testing" -) - -var testOutput = []byte("0123456789abcdefghijklmnopqrstuvwxy") -var testInput = []byte("012\n345\n678\n9ab\ncde\nfgh\nijk\nlmn\nopq\nrst\nuvw\nxy") -var testInputrn = []byte("012\r\n345\r\n678\r\n9ab\r\ncde\r\nfgh\r\nijk\r\nlmn\r\nopq\r\nrst\r\nuvw\r\nxy\r\n\n\r\n") - -// TestReader wraps a []byte and returns reads of a specific length. -type testReader struct { - data []byte - stride int -} - -func (t *testReader) Read(buf []byte) (n int, err os.Error) { - n = t.stride - if n > len(t.data) { - n = len(t.data) - } - if n > len(buf) { - n = len(buf) - } - copy(buf, t.data) - t.data = t.data[n:] - if len(t.data) == 0 { - err = os.EOF - } - return -} - -func testLineReader(t *testing.T, input []byte) { - for stride := 1; stride < len(input); stride++ { - done := 0 - reader := testReader{input, stride} - l := NewReader(&reader, len(input)+1) - for { - line, isPrefix, err := l.ReadLine() - if len(line) > 0 && err != nil { - t.Errorf("ReadLine returned both data and error: %s", err) - } - if isPrefix { - t.Errorf("ReadLine returned prefix") - } - if err != nil { - if err != os.EOF { - t.Fatalf("Got unknown error: %s", err) - } - break - } - if want := testOutput[done : done+len(line)]; !bytes.Equal(want, line) { - t.Errorf("Bad line at stride %d: want: %x got: %x", stride, want, line) - } - done += len(line) - } - if done != len(testOutput) { - t.Error("ReadLine didn't return everything") - } - } -} - -func TestReader(t *testing.T) { - testLineReader(t, testInput) - testLineReader(t, testInputrn) -} - -func TestLineTooLong(t *testing.T) { - buf := bytes.NewBuffer([]byte("aaabbbcc\n")) - l := NewReader(buf, 3) - line, isPrefix, err := l.ReadLine() - if !isPrefix || !bytes.Equal(line, []byte("aaa")) || err != nil { - t.Errorf("bad result for first line: %x %s", line, err) - } - line, isPrefix, err = l.ReadLine() - if !isPrefix || !bytes.Equal(line, []byte("bbb")) || err != nil { - t.Errorf("bad result for second line: %x", line) - } - line, isPrefix, err = l.ReadLine() - if isPrefix || !bytes.Equal(line, []byte("cc")) || err != nil { - t.Errorf("bad result for third line: %x", line) - } -} - -func TestReadAfterLines(t *testing.T) { - line1 := "line1" - restData := "line2\nline 3\n" - inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData)) - outbuf := new(bytes.Buffer) - maxLineLength := len(line1) + len(restData)/2 - l := NewReader(inbuf, maxLineLength) - line, isPrefix, err := l.ReadLine() - if isPrefix || err != nil || string(line) != line1 { - t.Errorf("bad result for first line: isPrefix=%v err=%v line=%q", isPrefix, err, string(line)) - } - n, err := io.Copy(outbuf, l) - if int(n) != len(restData) || err != nil { - t.Errorf("bad result for Read: n=%d err=%v", n, err) - } - if outbuf.String() != restData { - t.Errorf("bad result for Read: got %q; expected %q", outbuf.String(), restData) - } -} - -func TestReadEmptyBuffer(t *testing.T) { - l := NewReader(bytes.NewBuffer(nil), 10) - line, isPrefix, err := l.ReadLine() - if err != os.EOF { - t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err) - } -} - -func TestLinesAfterRead(t *testing.T) { - l := NewReader(bytes.NewBuffer([]byte("foo")), 10) - _, err := ioutil.ReadAll(l) - if err != nil { - t.Error(err) - return - } - - line, isPrefix, err := l.ReadLine() - if err != os.EOF { - t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err) - } -} diff --git a/src/pkg/encoding/pem/pem.go b/src/pkg/encoding/pem/pem.go index 44e3d0ad0..c2398807f 100644 --- a/src/pkg/encoding/pem/pem.go +++ b/src/pkg/encoding/pem/pem.go @@ -140,7 +140,7 @@ Error: // any lines which could be header lines. However, a valid preamble // line is not a valid header line, therefore we cannot have consumed // the preamble line for the any subsequent block. Thus, we will always - // find any valid block, no matter what bytes preceed it. + // find any valid block, no matter what bytes precede it. // // For example, if the input is // |