You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.8 KiB

  1. // Protocol Buffers for Go with Gadgets
  2. //
  3. // Copyright (c) 2013, The GoGo Authors. All rights reserved.
  4. // http://github.com/gogo/protobuf
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  21. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. //
  29. // Modified from original GoGo Protobuf to not buffer the reader.
  30. package protoio
  31. import (
  32. "bytes"
  33. "encoding/binary"
  34. "fmt"
  35. "io"
  36. "github.com/gogo/protobuf/proto"
  37. )
  38. // NewDelimitedReader reads varint-delimited Protobuf messages from a reader. Unlike the gogoproto
  39. // NewDelimitedReader, this does not buffer the reader, which may cause poor performance but is
  40. // necessary when only reading single messages (e.g. in the p2p package).
  41. func NewDelimitedReader(r io.Reader, maxSize int) ReadCloser {
  42. var closer io.Closer
  43. if c, ok := r.(io.Closer); ok {
  44. closer = c
  45. }
  46. return &varintReader{newByteReader(r), nil, maxSize, closer}
  47. }
  48. type varintReader struct {
  49. r *byteReader
  50. buf []byte
  51. maxSize int
  52. closer io.Closer
  53. }
  54. func (r *varintReader) ReadMsg(msg proto.Message) error {
  55. length64, err := binary.ReadUvarint(newByteReader(r.r))
  56. if err != nil {
  57. return err
  58. }
  59. length := int(length64)
  60. if length < 0 || length > r.maxSize {
  61. return fmt.Errorf("message exceeds max size (%v > %v)", length, r.maxSize)
  62. }
  63. if len(r.buf) < length {
  64. r.buf = make([]byte, length)
  65. }
  66. buf := r.buf[:length]
  67. if _, err := io.ReadFull(r.r, buf); err != nil {
  68. return err
  69. }
  70. return proto.Unmarshal(buf, msg)
  71. }
  72. func (r *varintReader) Close() error {
  73. if r.closer != nil {
  74. return r.closer.Close()
  75. }
  76. return nil
  77. }
  78. func UnmarshalDelimited(data []byte, msg proto.Message) error {
  79. return NewDelimitedReader(bytes.NewReader(data), len(data)).ReadMsg(msg)
  80. }