summaryrefslogtreecommitdiff
path: root/vendor/github.com/oschwald/maxminddb-golang/reader.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/oschwald/maxminddb-golang/reader.go')
-rw-r--r--vendor/github.com/oschwald/maxminddb-golang/reader.go259
1 files changed, 0 insertions, 259 deletions
diff --git a/vendor/github.com/oschwald/maxminddb-golang/reader.go b/vendor/github.com/oschwald/maxminddb-golang/reader.go
deleted file mode 100644
index 97b9607..0000000
--- a/vendor/github.com/oschwald/maxminddb-golang/reader.go
+++ /dev/null
@@ -1,259 +0,0 @@
-package maxminddb
-
-import (
- "bytes"
- "errors"
- "fmt"
- "net"
- "reflect"
-)
-
-const (
- // NotFound is returned by LookupOffset when a matched root record offset
- // cannot be found.
- NotFound = ^uintptr(0)
-
- dataSectionSeparatorSize = 16
-)
-
-var metadataStartMarker = []byte("\xAB\xCD\xEFMaxMind.com")
-
-// Reader holds the data corresponding to the MaxMind DB file. Its only public
-// field is Metadata, which contains the metadata from the MaxMind DB file.
-type Reader struct {
- hasMappedFile bool
- buffer []byte
- decoder decoder
- Metadata Metadata
- ipv4Start uint
-}
-
-// Metadata holds the metadata decoded from the MaxMind DB file. In particular
-// in has the format version, the build time as Unix epoch time, the database
-// type and description, the IP version supported, and a slice of the natural
-// languages included.
-type Metadata struct {
- BinaryFormatMajorVersion uint `maxminddb:"binary_format_major_version"`
- BinaryFormatMinorVersion uint `maxminddb:"binary_format_minor_version"`
- BuildEpoch uint `maxminddb:"build_epoch"`
- DatabaseType string `maxminddb:"database_type"`
- Description map[string]string `maxminddb:"description"`
- IPVersion uint `maxminddb:"ip_version"`
- Languages []string `maxminddb:"languages"`
- NodeCount uint `maxminddb:"node_count"`
- RecordSize uint `maxminddb:"record_size"`
-}
-
-// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns
-// a Reader structure or an error.
-func FromBytes(buffer []byte) (*Reader, error) {
- metadataStart := bytes.LastIndex(buffer, metadataStartMarker)
-
- if metadataStart == -1 {
- return nil, newInvalidDatabaseError("error opening database: invalid MaxMind DB file")
- }
-
- metadataStart += len(metadataStartMarker)
- metadataDecoder := decoder{buffer[metadataStart:]}
-
- var metadata Metadata
-
- rvMetdata := reflect.ValueOf(&metadata)
- _, err := metadataDecoder.decode(0, rvMetdata, 0)
- if err != nil {
- return nil, err
- }
-
- searchTreeSize := metadata.NodeCount * metadata.RecordSize / 4
- dataSectionStart := searchTreeSize + dataSectionSeparatorSize
- dataSectionEnd := uint(metadataStart - len(metadataStartMarker))
- if dataSectionStart > dataSectionEnd {
- return nil, newInvalidDatabaseError("the MaxMind DB contains invalid metadata")
- }
- d := decoder{
- buffer[searchTreeSize+dataSectionSeparatorSize : metadataStart-len(metadataStartMarker)],
- }
-
- reader := &Reader{
- buffer: buffer,
- decoder: d,
- Metadata: metadata,
- ipv4Start: 0,
- }
-
- reader.ipv4Start, err = reader.startNode()
-
- return reader, err
-}
-
-func (r *Reader) startNode() (uint, error) {
- if r.Metadata.IPVersion != 6 {
- return 0, nil
- }
-
- nodeCount := r.Metadata.NodeCount
-
- node := uint(0)
- var err error
- for i := 0; i < 96 && node < nodeCount; i++ {
- node, err = r.readNode(node, 0)
- if err != nil {
- return 0, err
- }
- }
- return node, err
-}
-
-// Lookup takes an IP address as a net.IP structure and a pointer to the
-// result value to Decode into.
-func (r *Reader) Lookup(ipAddress net.IP, result interface{}) error {
- if r.buffer == nil {
- return errors.New("cannot call Lookup on a closed database")
- }
- pointer, err := r.lookupPointer(ipAddress)
- if pointer == 0 || err != nil {
- return err
- }
- return r.retrieveData(pointer, result)
-}
-
-// LookupOffset maps an argument net.IP to a corresponding record offset in the
-// database. NotFound is returned if no such record is found, and a record may
-// otherwise be extracted by passing the returned offset to Decode. LookupOffset
-// is an advanced API, which exists to provide clients with a means to cache
-// previously-decoded records.
-func (r *Reader) LookupOffset(ipAddress net.IP) (uintptr, error) {
- if r.buffer == nil {
- return 0, errors.New("cannot call LookupOffset on a closed database")
- }
- pointer, err := r.lookupPointer(ipAddress)
- if pointer == 0 || err != nil {
- return NotFound, err
- }
- return r.resolveDataPointer(pointer)
-}
-
-// Decode the record at |offset| into |result|. The result value pointed to
-// must be a data value that corresponds to a record in the database. This may
-// include a struct representation of the data, a map capable of holding the
-// data or an empty interface{} value.
-//
-// If result is a pointer to a struct, the struct need not include a field
-// for every value that may be in the database. If a field is not present in
-// the structure, the decoder will not decode that field, reducing the time
-// required to decode the record.
-//
-// As a special case, a struct field of type uintptr will be used to capture
-// the offset of the value. Decode may later be used to extract the stored
-// value from the offset. MaxMind DBs are highly normalized: for example in
-// the City database, all records of the same country will reference a
-// single representative record for that country. This uintptr behavior allows
-// clients to leverage this normalization in their own sub-record caching.
-func (r *Reader) Decode(offset uintptr, result interface{}) error {
- if r.buffer == nil {
- return errors.New("cannot call Decode on a closed database")
- }
- return r.decode(offset, result)
-}
-
-func (r *Reader) decode(offset uintptr, result interface{}) error {
- rv := reflect.ValueOf(result)
- if rv.Kind() != reflect.Ptr || rv.IsNil() {
- return errors.New("result param must be a pointer")
- }
-
- _, err := r.decoder.decode(uint(offset), reflect.ValueOf(result), 0)
- return err
-}
-
-func (r *Reader) lookupPointer(ipAddress net.IP) (uint, error) {
- if ipAddress == nil {
- return 0, errors.New("ipAddress passed to Lookup cannot be nil")
- }
-
- ipV4Address := ipAddress.To4()
- if ipV4Address != nil {
- ipAddress = ipV4Address
- }
- if len(ipAddress) == 16 && r.Metadata.IPVersion == 4 {
- return 0, fmt.Errorf("error looking up '%s': you attempted to look up an IPv6 address in an IPv4-only database", ipAddress.String())
- }
-
- return r.findAddressInTree(ipAddress)
-}
-
-func (r *Reader) findAddressInTree(ipAddress net.IP) (uint, error) {
-
- bitCount := uint(len(ipAddress) * 8)
-
- var node uint
- if bitCount == 32 {
- node = r.ipv4Start
- }
-
- nodeCount := r.Metadata.NodeCount
-
- for i := uint(0); i < bitCount && node < nodeCount; i++ {
- bit := uint(1) & (uint(ipAddress[i>>3]) >> (7 - (i % 8)))
-
- var err error
- node, err = r.readNode(node, bit)
- if err != nil {
- return 0, err
- }
- }
- if node == nodeCount {
- // Record is empty
- return 0, nil
- } else if node > nodeCount {
- return node, nil
- }
-
- return 0, newInvalidDatabaseError("invalid node in search tree")
-}
-
-func (r *Reader) readNode(nodeNumber uint, index uint) (uint, error) {
- RecordSize := r.Metadata.RecordSize
-
- baseOffset := nodeNumber * RecordSize / 4
-
- var nodeBytes []byte
- var prefix uint
- switch RecordSize {
- case 24:
- offset := baseOffset + index*3
- nodeBytes = r.buffer[offset : offset+3]
- case 28:
- prefix = uint(r.buffer[baseOffset+3])
- if index != 0 {
- prefix &= 0x0F
- } else {
- prefix = (0xF0 & prefix) >> 4
- }
- offset := baseOffset + index*4
- nodeBytes = r.buffer[offset : offset+3]
- case 32:
- offset := baseOffset + index*4
- nodeBytes = r.buffer[offset : offset+4]
- default:
- return 0, newInvalidDatabaseError("unknown record size: %d", RecordSize)
- }
- return uintFromBytes(prefix, nodeBytes), nil
-}
-
-func (r *Reader) retrieveData(pointer uint, result interface{}) error {
- offset, err := r.resolveDataPointer(pointer)
- if err != nil {
- return err
- }
- return r.decode(offset, result)
-}
-
-func (r *Reader) resolveDataPointer(pointer uint) (uintptr, error) {
- var resolved = uintptr(pointer - r.Metadata.NodeCount - dataSectionSeparatorSize)
-
- if resolved > uintptr(len(r.buffer)) {
- return 0, newInvalidDatabaseError("the MaxMind DB file's search tree is corrupt")
- }
- return resolved, nil
-}