package wire import ( "encoding/binary" "fmt" "io" "os" "time" ) type SyncScanner interface { // ReadOctetString reads a 4-byte string. ReadOctetString() (string, error) ReadInt32() (int32, error) ReadFileMode() (os.FileMode, error) ReadTime() (time.Time, error) // Reads an octet length, followed by length bytes. ReadString() (string, error) // Reads an octet length, and returns a reader that will read length // bytes (see io.LimitReader). The returned reader should be fully // read before reading anything off the Scanner again. ReadBytes() (io.Reader, error) // Closes the underlying reader. Close() error } type realSyncScanner struct { io.Reader } func NewSyncScanner(r io.Reader) SyncScanner { return &realSyncScanner{r} } func RequireOctetString(s SyncScanner, expected string) error { actual, err := s.ReadOctetString() if err != nil { return fmt.Errorf("expected to read '%s', got err: %v", expected, err) } if actual != expected { return fmt.Errorf("expected to read '%s', got '%s'", expected, actual) } return nil } func (s *realSyncScanner) ReadOctetString() (string, error) { octet := make([]byte, 4) n, err := io.ReadFull(s.Reader, octet) if err != nil && err != io.ErrUnexpectedEOF { return "", err } else if err == io.ErrUnexpectedEOF { return "", incompleteMessage("octet", n, 4) } return string(octet), nil } func (s *realSyncScanner) ReadInt32() (int32, error) { var value int32 err := binary.Read(s.Reader, binary.LittleEndian, &value) return value, err } func (s *realSyncScanner) ReadFileMode() (filemode os.FileMode, err error) { var value uint32 err = binary.Read(s.Reader, binary.LittleEndian, &value) if err == nil { filemode = ParseFileModeFromAdb(value) } return } func (s *realSyncScanner) ReadTime() (time.Time, error) { seconds, err := s.ReadInt32() if err != nil { return time.Time{}, err } return time.Unix(int64(seconds), 0).UTC(), nil } func (s *realSyncScanner) ReadString() (string, error) { length, err := s.ReadInt32() if err != nil { return "", err } bytes := make([]byte, length) n, err := io.ReadFull(s.Reader, bytes) if err != nil && err != io.ErrUnexpectedEOF { return "", err } else if err == io.ErrUnexpectedEOF { return "", incompleteMessage("bytes", n, int(length)) } return string(bytes), nil } func (s *realSyncScanner) ReadBytes() (io.Reader, error) { length, err := s.ReadInt32() if err != nil { return nil, err } return io.LimitReader(s.Reader, int64(length)), nil } func (s *realSyncScanner) Close() error { if closer, ok := s.Reader.(io.Closer); ok { return closer.Close() } return nil }