imposm3/parser/pbf/lowlevel.go

217 lines
4.6 KiB
Go
Raw Normal View History

package pbf
2013-02-12 22:45:49 +04:00
import (
"bytes"
"compress/zlib"
structs "encoding/binary"
"errors"
"fmt"
2013-02-12 22:45:49 +04:00
"io"
"log"
"os"
"time"
2015-04-28 10:18:38 +03:00
2017-11-15 15:57:30 +03:00
"github.com/gogo/protobuf/proto"
2016-12-06 17:36:16 +03:00
"github.com/omniscale/imposm3/parser/pbf/internal/osmpbf"
2013-02-12 22:45:49 +04:00
)
2015-04-28 10:18:38 +03:00
type block struct {
filename string
offset int64
size int32
}
type parserError struct {
message string
originalError error
}
func (e *parserError) Error() string {
return fmt.Sprintf("%s: %v", e.message, e.originalError)
}
func newParserError(message string, err error) *parserError {
return &parserError{message, err}
}
var supportedFeatured = map[string]bool{"OsmSchema-V0.6": true, "DenseNodes": true}
2015-04-28 10:18:38 +03:00
func readBlobData(pos block) ([]byte, error) {
2013-07-05 11:57:03 +04:00
file, err := os.Open(pos.filename)
2013-02-12 22:45:49 +04:00
if err != nil {
return nil, newParserError("file open", err)
2013-02-12 22:45:49 +04:00
}
defer file.Close()
var blob = &osmpbf.Blob{}
2013-07-05 11:57:03 +04:00
blobData := make([]byte, pos.size)
2018-06-05 22:22:26 +03:00
if _, err := file.Seek(pos.offset, 0); err != nil {
return nil, err
}
if n, err := io.ReadFull(file, blobData); n != int(pos.size) || err != nil {
return nil, newParserError("reading blob data", err)
}
2013-02-12 22:45:49 +04:00
err = proto.Unmarshal(blobData, blob)
if err != nil {
return nil, newParserError("unmarshaling blob", err)
2013-02-12 22:45:49 +04:00
}
2013-07-05 12:06:55 +04:00
// pbf contains (uncompressed) raw or zlibdata
raw := blob.GetRaw()
if raw == nil {
buf := bytes.NewBuffer(blob.GetZlibData())
r, err := zlib.NewReader(buf)
if err != nil {
return nil, newParserError("zlib error", err)
2013-07-05 12:06:55 +04:00
}
raw = make([]byte, blob.GetRawSize())
_, err = io.ReadFull(r, raw)
if err != nil {
return nil, newParserError("zlib read error", err)
2013-07-05 12:06:55 +04:00
}
2013-02-12 22:45:49 +04:00
}
return raw, nil
}
2013-02-12 22:45:49 +04:00
2015-04-28 10:18:38 +03:00
func readPrimitiveBlock(pos block) *osmpbf.PrimitiveBlock {
raw, err := readBlobData(pos)
if err != nil {
log.Panic(err)
}
block := &osmpbf.PrimitiveBlock{}
2013-02-12 22:45:49 +04:00
err = proto.Unmarshal(raw, block)
if err != nil {
log.Panic("unmarshaling error: ", err)
}
return block
}
2016-12-06 16:47:34 +03:00
func readAndParseHeaderBlock(pos block) (*Header, error) {
raw, err := readBlobData(pos)
if err != nil {
return nil, err
}
header := &osmpbf.HeaderBlock{}
err = proto.Unmarshal(raw, header)
if err != nil {
return nil, err
}
for _, feature := range header.RequiredFeatures {
if supportedFeatured[feature] != true {
return nil, errors.New("cannot parse file, feature " + feature + " not supported")
}
}
2016-12-06 16:47:34 +03:00
result := &Header{}
timestamp := header.GetOsmosisReplicationTimestamp()
result.Time = time.Unix(timestamp, 0 /* nanoseconds */)
result.Sequence = header.GetOsmosisReplicationSequenceNumber()
2016-09-13 11:21:28 +03:00
result.RequiredFeatures = header.RequiredFeatures
result.OptionalFeatures = header.OptionalFeatures
return result, nil
}
2016-12-06 16:47:34 +03:00
type pbf struct {
2013-07-05 11:57:03 +04:00
file *os.File
2016-12-06 16:47:34 +03:00
filename string
2013-07-05 11:57:03 +04:00
offset int64
2016-12-06 16:47:34 +03:00
header *Header
2013-07-05 11:57:03 +04:00
}
2016-12-06 16:47:34 +03:00
type Header struct {
Time time.Time
Sequence int64
2016-12-06 16:47:34 +03:00
Filename string
2016-09-13 11:21:28 +03:00
RequiredFeatures []string
OptionalFeatures []string
}
2016-12-06 16:47:34 +03:00
func open(filename string) (f *pbf, err error) {
2013-07-05 11:57:03 +04:00
file, err := os.Open(filename)
if err != nil {
return nil, err
}
2016-12-06 16:47:34 +03:00
f = &pbf{filename: filename, file: file}
err = f.parseHeader()
if err != nil {
file.Close()
return nil, err
}
2013-07-05 11:57:03 +04:00
return f, nil
}
2016-12-06 16:47:34 +03:00
func (pbf *pbf) close() error {
2013-07-05 11:57:03 +04:00
return pbf.file.Close()
}
2016-12-06 16:47:34 +03:00
func (pbf *pbf) parseHeader() error {
offset, size, header := pbf.nextBlock()
if header.GetType() != "OSMHeader" {
panic("invalid block type, expected OSMHeader, got " + header.GetType())
}
var err error
2016-12-06 16:47:34 +03:00
pbf.header, err = readAndParseHeaderBlock(block{pbf.filename, offset, size})
pbf.header.Filename = pbf.filename
return err
}
2016-12-06 16:47:34 +03:00
func (pbf *pbf) nextBlock() (offset int64, size int32, header *osmpbf.BlobHeader) {
header = pbf.nextBlobHeader()
2013-07-05 11:57:03 +04:00
size = header.GetDatasize()
offset = pbf.offset
pbf.offset += int64(size)
pbf.file.Seek(pbf.offset, 0)
return offset, size, header
2013-07-05 11:57:03 +04:00
}
2016-12-06 16:47:34 +03:00
func (pbf *pbf) BlockPositions() (positions chan block) {
2015-04-28 10:18:38 +03:00
positions = make(chan block, 8)
2013-02-12 22:45:49 +04:00
go func() {
for {
offset, size, header := pbf.nextBlock()
2013-02-12 22:45:49 +04:00
if size == 0 {
close(positions)
2016-12-06 16:47:34 +03:00
pbf.close()
2013-02-12 22:45:49 +04:00
return
}
if header.GetType() != "OSMData" {
panic("invalid block type, expected OSMData, got " + header.GetType())
}
2016-12-06 16:47:34 +03:00
positions <- block{pbf.filename, offset, size}
2013-02-12 22:45:49 +04:00
}
}()
return
}
2016-12-06 16:47:34 +03:00
func (pbf *pbf) nextBlobHeaderSize() (size int32) {
2013-02-12 22:45:49 +04:00
pbf.offset += 4
structs.Read(pbf.file, structs.BigEndian, &size)
return
}
2016-12-06 16:47:34 +03:00
func (pbf *pbf) nextBlobHeader() *osmpbf.BlobHeader {
2013-02-12 22:45:49 +04:00
var blobHeader = &osmpbf.BlobHeader{}
size := pbf.nextBlobHeaderSize()
if size == 0 {
return blobHeader
}
data := make([]byte, size)
io.ReadFull(pbf.file, data)
err := proto.Unmarshal(data, blobHeader)
if err != nil {
log.Fatal("unmarshaling error (header): ", err)
}
pbf.offset += int64(size)
return blobHeader
}