goadb/wire/sync_scanner.go
2015-04-28 14:25:36 -05:00

113 lines
2.6 KiB
Go

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
}