ReadonlyheaderThe file's header (Section 5), including its attribution.
ReadonlydirectoryThe file's directory (Section 6): where each chunk is.
How many countries, regions and cities the file has.
StaticopenOpens a CGEODATA file: reads and validates its header, directory and
the uncompressed part of its place table (Sections 5-7.2), and
nothing else -- chunks and names are read on first use. The reader
takes ownership of input, if it's a ByteSource: close() closes
it, as does a failed open.
Closes the source, and any index this reader opened itself.
The country, region and city a point lies in: Section 9's lookup
procedure (lookup()) with the names resolved (place()). Rejects
with a RangeError for a latitude outside [-90, 90) or a longitude
outside [-180, 180).
Section 9's lookup procedure: the place a point lies in, as an id, and
the cell the answer holds for. Reads and decodes the point's chunk if
it isn't cached; resolve the id with place() or placeIds().
lookup() answered from memory only: the same result when the
point's chunk is already decoded, undefined when answering would
need a read. For callers doing many lookups close together, which
mostly hit the same few chunks:
const result = reader.lookupCached(lat, lon) ?? (await reader.lookup(lat, lon));
waits only for the lookups that actually read something.
The index of the chunk a point lies in (Section 6.1).
The names of one place by global id, without resolving its ancestors.
Cheaper than place() when only the names are needed.
FNV-1a 64-bit hash of the place table bytes, as defined by binary-format.md Section B.6. Used to bind a search index to its source.
FNV-1a 64-bit hash of everything before the first chunk -- header, directory and place table -- as defined by binary-format.md Section C.4. Binds a locate index to its source: the chunk lengths it covers change whenever the chunks do.
Attaches a text search index (Appendix B, built by buildSearchIndex
/ cgeodata build-search-index) so search() only checks the places
the index says could match instead of every place. Results are
identical with or without it -- only the speed differs.
Takes the index's file (as for open(); read on demand) or an open
SearchIndex (which the caller keeps ownership of), or undefined to
search without one. Replaces OpenOptions.searchIndex. Rejects with
a CGeoDataIndexMismatchError if it was built from a different file.
Whether search() will use an index. Reads (and validates) the one
from OpenOptions.searchIndex if that hasn't happened yet.
Attaches a locate index (Appendix C, built by buildLocateIndex /
cgeodata build-locate-index) so locate() reads one entry instead
of scanning every chunk. Results are identical with or without it --
only the speed differs -- except that its areas also let a sorted
search() rank equal matches by size (SearchOptions.areaTieBreak).
Takes the index's file (as for open(); read on demand) or an open
LocateIndex (which the caller keeps ownership of), or undefined to
locate without one. Replaces OpenOptions.locateIndex. Rejects with
a CGeoDataIndexMismatchError if it was built from a different file.
Whether locate() will use an index. Reads (and validates) the one
from OpenOptions.locateIndex if that hasn't happened yet.
Resolves one place id (Section 7.5) to its names and ancestors.
place() without the names: the place's level and the global ids
of it and its ancestors, from the place table's counts alone, so no
name block is read -- and so synchronous.
How many places sit directly under id: a country's regions, a
region's cities, always 0 for a city. From the place table's counts
alone, like placeIds(), so no name block is read and it is
synchronous: childCount(region) === 0 finds a region with no city
mapped to it.
Walks the place hierarchy in id order (countries, then regions, then cities), optionally restricted to one level and/or one ancestor. Each level's ids for a given parent are contiguous (Section 7.5), so a filtered walk only touches the ids it yields.
Diacritic- and case-insensitive substring match against every name of
every place (all levels unless filtered) -- Section B.5's "matches":
the folded form (foldDiacritics) of a name contains the folded form
of the query. Without a search index this is a plain linear scan over
the name blocks; with one (useSearchIndex()), only the places the
index can't rule out are compared. Same results either way.
A text with commas also reads as a place and the places it lies in (Appendix B.13): "Paris, Texas" finds a place named "Paris, Texas" and every "Paris" whose region or country matches "Texas"; "Springfield, Illinois, United States" narrows by both. Each part after a comma has to match a different ancestor, nearest first.
The area byte (binary-format.md Section C.3) of every place, by id --
the size of the place and everything under it, on a log scale, a
quarter of a doubling per step -- read from the attached locate index
(useLocateIndex()), or undefined without one. What
search({ sort: true }) breaks ties with (SearchOptions.areaTieBreak).
Read once and then kept; the array is shared, so don't modify it.
The parsed records of one chunk (Section 8), or undefined when the
chunk is empty. Cached like lookups, unless cache is false: a
one-pass walk over every chunk should skip the cache, so it doesn't
evict everything lookups had cached for chunks it only visits once.
A representative lat/lon for a place id: the centre of the place's
representative cell (binary-format.md Section C.3), a cell near the
middle of the place's area -- its own cells plus those of every place
under it -- that is guaranteed to lie in that area, so query() at
the returned point resolves to the place or one of its descendants.
const position = await reader.locate(place.id);
if (position) map.setView([position.lat, position.lon]);
Null if neither the place nor anything under it has any cells -- and
that happens to real places, not only to broken files: a place
smaller than the file's finest cell (a tiny island, an enclave, a
boundary sliver) loses every cell to its neighbours. On a worldwide
build that's about 0.15% of places, every one of them still found
by search(); drop them from results that need a position rather
than defaulting to a coordinate.
With a locate index (useLocateIndex()) this reads one entry;
without one it scans every chunk. Same result either way.
The ids of place id and of every place under it, as half-open
ranges: [id, id + 1] first, then for a country its regions and
their cities, for a region its cities. Each level's children are
contiguous (Section 7.1), so this is at most three ranges.
One chunk's records with their cells and places resolved -- what a lookup in that chunk can answer with, laid out for inspection.
A CGEODATA file opened for reading: answers which country, region and city a point lies in (
query,lookup), what a place is called and where it sits in the hierarchy (place,placeIds), which places match a name (search), and where a place is (locate).Opening reads only the header, directory and place counts; each lookup reads and decodes the one chunk its point lies in, which then stays cached (
OpenOptions.cacheBytes).Example