@@ -5,8 +5,11 @@ import (
55 "bytes"
66 "errors"
77 "fmt"
8+ "io"
89 "net/netip"
10+ "os"
911 "reflect"
12+ "runtime"
1013)
1114
1215const dataSectionSeparatorSize = 16
@@ -45,6 +48,70 @@ type Metadata struct {
4548 RecordSize uint `maxminddb:"record_size"`
4649}
4750
51+ // Open takes a string path to a MaxMind DB file and returns a Reader
52+ // structure or an error. The database file is opened using a memory map
53+ // on supported platforms. On platforms without memory map support, such
54+ // as WebAssembly or Google App Engine, the database is loaded into memory.
55+ // Use the Close method on the Reader object to return the resources to the system.
56+ func Open (file string ) (* Reader , error ) {
57+ mapFile , err := os .Open (file )
58+ if err != nil {
59+ return nil , err
60+ }
61+ defer mapFile .Close ()
62+
63+ stats , err := mapFile .Stat ()
64+ if err != nil {
65+ return nil , err
66+ }
67+
68+ size64 := stats .Size ()
69+ size := int (size64 )
70+ if int64 (size ) != size64 {
71+ return nil , errors .New ("file too large" )
72+ }
73+
74+ data , err := mmap (int (mapFile .Fd ()), size )
75+ if err != nil {
76+ if errors .Is (err , errors .ErrUnsupported ) {
77+ data , err = openFallback (mapFile , size )
78+ if err != nil {
79+ return nil , err
80+ }
81+ return FromBytes (data )
82+ }
83+ return nil , err
84+ }
85+
86+ reader , err := FromBytes (data )
87+ if err != nil {
88+ _ = munmap (data )
89+ return nil , err
90+ }
91+
92+ reader .hasMappedFile = true
93+ runtime .SetFinalizer (reader , (* Reader ).Close )
94+ return reader , nil
95+ }
96+
97+ func openFallback (f * os.File , size int ) (data []byte , err error ) {
98+ data = make ([]byte , size )
99+ _ , err = io .ReadFull (f , data )
100+ return data , err
101+ }
102+
103+ // Close returns the resources used by the database to the system.
104+ func (r * Reader ) Close () error {
105+ var err error
106+ if r .hasMappedFile {
107+ runtime .SetFinalizer (r , nil )
108+ r .hasMappedFile = false
109+ err = munmap (r .buffer )
110+ }
111+ r .buffer = nil
112+ return err
113+ }
114+
48115// FromBytes takes a byte slice corresponding to a MaxMind DB file and returns
49116// a Reader structure or an error.
50117func FromBytes (buffer []byte ) (* Reader , error ) {
0 commit comments