@ferrybig/cgeodata-reader 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +313 -2
  3. package/binary-format.md +2620 -0
  4. package/dist/cache.d.ts +24 -0
  5. package/dist/cache.js +60 -0
  6. package/dist/cellBounds.d.ts +19 -0
  7. package/dist/cellBounds.js +36 -0
  8. package/dist/chunk.d.ts +35 -0
  9. package/dist/chunk.js +277 -0
  10. package/dist/chunkDecoder.d.ts +39 -0
  11. package/dist/chunkDecoder.js +116 -0
  12. package/dist/chunkDecoderWasm.d.ts +2 -0
  13. package/dist/chunkDecoderWasm.js +4 -0
  14. package/dist/cli/buildLocateIndex.d.ts +2 -0
  15. package/dist/cli/buildLocateIndex.js +46 -0
  16. package/dist/cli/buildSearchIndex.d.ts +2 -0
  17. package/dist/cli/buildSearchIndex.js +90 -0
  18. package/dist/cli/chunk.d.ts +2 -0
  19. package/dist/cli/chunk.js +67 -0
  20. package/dist/cli/info.d.ts +2 -0
  21. package/dist/cli/info.js +87 -0
  22. package/dist/cli/list.d.ts +2 -0
  23. package/dist/cli/list.js +71 -0
  24. package/dist/cli/locate.d.ts +2 -0
  25. package/dist/cli/locate.js +64 -0
  26. package/dist/cli/lookup.d.ts +2 -0
  27. package/dist/cli/lookup.js +128 -0
  28. package/dist/cli/search.d.ts +2 -0
  29. package/dist/cli/search.js +119 -0
  30. package/dist/cli/shared.d.ts +50 -0
  31. package/dist/cli/shared.js +140 -0
  32. package/dist/cli/show.d.ts +2 -0
  33. package/dist/cli/show.js +38 -0
  34. package/dist/cli.d.ts +2 -0
  35. package/dist/cli.js +107 -0
  36. package/dist/container.d.ts +17 -0
  37. package/dist/container.js +68 -0
  38. package/dist/directory.d.ts +21 -0
  39. package/dist/directory.js +31 -0
  40. package/dist/errors.d.ts +52 -0
  41. package/dist/errors.js +56 -0
  42. package/dist/format.d.ts +22 -0
  43. package/dist/format.js +23 -0
  44. package/dist/header.d.ts +30 -0
  45. package/dist/header.js +69 -0
  46. package/dist/index.d.ts +20 -0
  47. package/dist/index.js +18 -0
  48. package/dist/indexes.d.ts +11 -0
  49. package/dist/indexes.js +12 -0
  50. package/dist/inflate.d.ts +21 -0
  51. package/dist/inflate.js +61 -0
  52. package/dist/locateIndex.d.ts +142 -0
  53. package/dist/locateIndex.js +561 -0
  54. package/dist/morton.d.ts +28 -0
  55. package/dist/morton.js +51 -0
  56. package/dist/node.d.ts +65 -0
  57. package/dist/node.js +137 -0
  58. package/dist/placeTable.d.ts +69 -0
  59. package/dist/placeTable.js +177 -0
  60. package/dist/rangeChunk.d.ts +46 -0
  61. package/dist/rangeChunk.js +401 -0
  62. package/dist/rangeDecoder.d.ts +17 -0
  63. package/dist/rangeDecoder.js +129 -0
  64. package/dist/rangeDecoderWasm.d.ts +2 -0
  65. package/dist/rangeDecoderWasm.js +4 -0
  66. package/dist/reader.d.ts +534 -0
  67. package/dist/reader.js +1132 -0
  68. package/dist/relevance.d.ts +184 -0
  69. package/dist/relevance.js +266 -0
  70. package/dist/searchIndex.d.ts +148 -0
  71. package/dist/searchIndex.js +786 -0
  72. package/dist/source.d.ts +49 -0
  73. package/dist/source.js +50 -0
  74. package/dist/turns.d.ts +19 -0
  75. package/dist/turns.js +40 -0
  76. package/dist/varint.d.ts +52 -0
  77. package/dist/varint.js +137 -0
  78. package/package.json +76 -5
@@ -0,0 +1,2620 @@
1
+ # CGEODATA: A Compact Binary Format for Reverse Geocoding
2
+
3
+ Version 1 (draft)
4
+
5
+ ## Abstract
6
+
7
+ This document specifies CGEODATA, a binary file format that maps a WGS84
8
+ coordinate to the country, region, and city that contain it, and that
9
+ carries a searchable list of those places. The format stores a quadtree
10
+ partition of the world as its leaf cells in Morton order, split into
11
+ independently compressed chunks so that a lookup reads only a small part of the file.
12
+ The place list is stored as delta-coded hierarchy counts plus
13
+ keyframe-compressed name blocks, so that names can be recovered by index
14
+ without decompressing the whole list.
15
+
16
+ ## Table of Contents
17
+
18
+ 1. [Introduction](#1-introduction)
19
+ 2. [Conventions and Terminology](#2-conventions-and-terminology)
20
+ 3. [Primitive Types](#3-primitive-types)
21
+ 4. [File Layout](#4-file-layout)
22
+ 5. [Header](#5-header)
23
+ 6. [Directory](#6-directory)
24
+ 7. [Place Table](#7-place-table)
25
+ 8. [Chunks](#8-chunks)
26
+ 9. [Lookup Procedure](#9-lookup-procedure)
27
+ 10. [Encoder Considerations](#10-encoder-considerations)
28
+ 11. [Robustness and Security Considerations](#11-robustness-and-security-considerations)
29
+ 12. [Open Issues](#12-open-issues)
30
+ - [Appendix A. Worked Example](#appendix-a-worked-example)
31
+ - [Appendix B. Text Search Index](#appendix-b-text-search-index)
32
+ - [Appendix C. Place Location Index](#appendix-c-place-location-index)
33
+ - [Appendix D. References](#appendix-d-references)
34
+
35
+ ## 1. Introduction
36
+
37
+ ### 1.1. Motivation
38
+
39
+ Reverse geocoding for photo management (see the project's [README](https://github.com/ferrybig/loc-to-city#readme))
40
+ is commonly implemented by storing one labelled point per place and
41
+ returning the nearest label. Cities are not points, and near any border
42
+ the nearest label is frequently wrong. Storing full polygons is accurate
43
+ but large and requires polygon arithmetic at query time.
44
+
45
+ CGEODATA stores the result of point-in-polygon classification instead of
46
+ the polygons: the world is recursively subdivided into cells until each
47
+ cell is attributed to a single place, and the resulting leaf cells are
48
+ stored in Morton order. A lookup is then one binary search.
49
+
50
+ ### 1.2. Design Goals
51
+
52
+ The format is designed with the following goals, in rough priority order:
53
+
54
+ 1. **Small on disk.** The place names and the spatial index together
55
+ should be far smaller than a worldwide nearest-point table.
56
+ 2. **Partial reads.** A reader MUST be able to answer a lookup by reading
57
+ and decompressing only a small, bounded part of the file, without
58
+ loading the entire file into memory. The file is expected to be large
59
+ at worldwide scale.
60
+ 3. **Fast lookups** after a modest one-time load of the directory.
61
+ 4. **Adequate accuracy for geotagging.** The target cell resolution is on
62
+ the order of a few hundred metres; the format itself supports finer
63
+ resolution at the cost of size.
64
+ 5. **Searchable place names.** The place list supports listing and text
65
+ search over countries, regions, and cities, and resolving a place to
66
+ its parents. An optional sidecar index
67
+ ([Appendix B](#appendix-b-text-search-index)) speeds up text search
68
+ without changing the file, and another
69
+ ([Appendix C](#appendix-c-place-location-index)) gives each place a
70
+ representative coordinate.
71
+ 6. **Implementable with no dependencies in JavaScript** (Node.js and
72
+ browsers) as well as other languages: only zlib, integer arithmetic,
73
+ and binary search are required.
74
+
75
+ ### 1.3. Non-Goals
76
+
77
+ - The format does not store polygon geometry and cannot answer
78
+ distance-to-border or area queries.
79
+ - The file itself does not store a representative coordinate per place.
80
+ One is defined by the chunks ([Section C.3](#c3-representative-cell))
81
+ and can be precomputed into an optional sidecar file
82
+ ([Appendix C](#appendix-c-place-location-index)).
83
+ - The format does not attempt exact answers at borders; cells that remain
84
+ ambiguous at the maximum depth are attributed to one place by the
85
+ encoder.
86
+
87
+ ## 2. Conventions and Terminology
88
+
89
+ ### 2.1. Requirements Language
90
+
91
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
92
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
93
+ "OPTIONAL" in this document are to be interpreted as described in BCP 14
94
+ [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as
95
+ shown here.
96
+
97
+ ### 2.2. Terms
98
+
99
+ - **Byte**: an octet, 8 bits.
100
+ - **Writer**, **encoder**: software that produces a CGEODATA file.
101
+ - **Reader**, **decoder**: software that consumes a CGEODATA file.
102
+ - **Place**: a country, region, or city. Every place has an
103
+ **identifier** (ID), which is its zero-based position in the place
104
+ table ([Section 7](#7-place-table)).
105
+ - **Chunk grid**: the fixed rectangular grid of `W × H` chunks that
106
+ covers the world ([Section 6.1](#61-chunk-grid)).
107
+ - **Chunk**: one cell of the chunk grid, together with its stored
108
+ spatial index ([Section 8](#8-chunks)). The stored form is one
109
+ independently compressed block.
110
+ - **Cell**: a rectangular area produced by quadtree subdivision of a
111
+ chunk. A cell at depth `d` is `2^d` times smaller than the chunk in each
112
+ direction.
113
+ - **Record**: one leaf cell stored in a chunk, attributing that cell to
114
+ one place (or to no place).
115
+ - **Morton code** (also Z-order code): the integer obtained by
116
+ interleaving the bits of a cell's row and column, so that quadtree
117
+ order becomes numeric order ([Section 8.1](#81-cell-grid-and-morton-codes)).
118
+ - **Unknown**: the lookup result for a coordinate that no record
119
+ attributes to a place.
120
+
121
+ ### 2.3. Coordinate System
122
+
123
+ All coordinates are WGS84 latitude and longitude in decimal degrees. A
124
+ valid latitude satisfies `-90 <= lat < 90`. A valid longitude satisfies
125
+ `-180 <= lon < 180`. Readers MUST reject coordinates outside these ranges.
126
+ Readers do not normalise longitude; a caller that wishes to accept
127
+ `lon = 180` or values outside the range MUST wrap them itself before the
128
+ lookup.
129
+
130
+ All intervals in this document are half-open: `[a, b)` includes `a` and
131
+ excludes `b`. The world grid is equirectangular: cells are equal in
132
+ degrees, not in metres.
133
+
134
+ ## 3. Primitive Types
135
+
136
+ ### 3.1. Fixed-Width Integers
137
+
138
+ `u8` is one byte. `u16`, `u24`, `u32`, and `u64` are unsigned integers of
139
+ 2, 3, 4, and 8 bytes, stored least significant byte first
140
+ (little-endian). `u64` is used only for checksums; a reader never needs
141
+ its value as a number and can compare it byte by byte, which sidesteps
142
+ the 53-bit integer limit of JavaScript.
143
+
144
+ ### 3.2. Variable-Length Integers (varint)
145
+
146
+ A `varint` is an unsigned integer encoded as in unsigned LEB128 (the
147
+ "base 128 varint" of Protocol Buffers):
148
+
149
+ - Each byte carries 7 bits of the value in its low bits.
150
+ - The high bit (`0x80`) is a continuation flag: `1` means another byte
151
+ follows, `0` marks the last byte.
152
+ - Groups are stored least significant first. The decoder accumulates
153
+ `byte & 0x7F` shifted left by `7 × i` for the `i`-th byte, and stops
154
+ after the first byte whose high bit is clear.
155
+
156
+ Every varint in this format MUST be less than `2^53`, so that it can be
157
+ represented exactly as an IEEE 754 double. An encoding therefore never
158
+ exceeds 8 bytes; readers MUST reject a varint longer than 8 bytes.
159
+ Writers MUST use the shortest encoding (no trailing `0x80 0x00`
160
+ padding). Readers MAY reject non-minimal encodings.
161
+
162
+ Examples: `0` is `00`; `127` is `7f`; `128` is `80 01`; `300` is
163
+ `ac 02`; `8192` is `80 40`.
164
+
165
+ ### 3.3. Delta-Coded Lists
166
+
167
+ Several lists in this format are stored delta-coded: each stored varint is
168
+ the difference between an element and the element before it, with an
169
+ implicit previous element of `0` before the first. A delta-coded list is
170
+ therefore always non-decreasing; where this document says "strictly
171
+ increasing", every stored delta after the first MUST be at least `1`.
172
+
173
+ ### 3.4. Strings
174
+
175
+ Strings are UTF-8 [RFC3629]. The header's attribution string is length
176
+ prefixed. Place names are `NUL` (`0x00`) terminated inside their
177
+ compressed block and MUST NOT contain `NUL`.
178
+
179
+ ### 3.5. Compressed Blocks
180
+
181
+ A compressed block is one complete zlib stream [RFC1950] containing
182
+ DEFLATE data [RFC1951]. Every compressed block in this format is
183
+ self-contained: it can be inflated without any other block. Readers
184
+ locate a block by the byte lengths recorded in the file, not by scanning
185
+ for stream boundaries.
186
+
187
+ In a version `2` file ([Section 5](#5-header)) chunks are not compressed
188
+ blocks: a chunk is stored as [Section 8.7](#87-version-2-chunks) lays it
189
+ out, with its own entropy coding. Name blocks are compressed blocks in
190
+ every version.
191
+
192
+ ## 4. File Layout
193
+
194
+ A CGEODATA file consists of four consecutive sections, with no padding or
195
+ alignment between or within them:
196
+
197
+ ```
198
+ +---------------------------+
199
+ | Header (Sec. 5) | fixed fields, uncompressed
200
+ +---------------------------+
201
+ | Directory (Sec. 6) | place table length + chunk length table
202
+ +---------------------------+
203
+ | Place table (Sec. 7) | hierarchy counts + compressed name blocks
204
+ +---------------------------+
205
+ | Chunk 0 (Sec. 8) | one compressed block, or absent if empty
206
+ | Chunk 1 |
207
+ | ... |
208
+ | Chunk W*H - 1 |
209
+ +---------------------------+
210
+ ```
211
+
212
+ The header and directory are small and are expected to be read once and
213
+ kept in memory. The place table's uncompressed prefix is also small. The
214
+ compressed name blocks and the chunks are read on demand.
215
+
216
+ The file has no trailer. The end of the last chunk is the end of the
217
+ file.
218
+
219
+ Derived sidecar files, such as the text search index of
220
+ [Appendix B](#appendix-b-text-search-index) and the place location index
221
+ of [Appendix C](#appendix-c-place-location-index), are separate files that
222
+ share the signature and the version field's kind mechanism
223
+ ([Section 5](#5-header)). They are never embedded in a CGEODATA file,
224
+ and a CGEODATA file never refers to them.
225
+
226
+ ## 5. Header
227
+
228
+ | Field | Type | Description |
229
+ |----------------------|------------|-------------|
230
+ | `signature` | 8 bytes | The ASCII bytes `CGEODATA` (`43 47 45 4f 44 41 54 41`). |
231
+ | `version` | varint | File kind and format version, `kind × 16 + version`. A CGEODATA file is kind `0`; this document specifies version `2`, so the field is `2`. See below. |
232
+ | `attribution_length` | varint | Byte length of `attribution`. |
233
+ | `attribution` | bytes | UTF-8 text, MAY contain Markdown, intended for display to humans, for example `[OpenStreetMap](https://openstreetmap.org/copyright)`. MAY be empty. |
234
+ | `width_exp` | u8 | The chunk grid has `W = 2^width_exp` columns. |
235
+ | `height_exp` | u8 | The chunk grid has `H = 2^height_exp` rows. |
236
+ | `max_depth` | u8 | The maximum quadtree depth `D` inside a chunk. Every Morton code in the file is `2 × D` bits wide. |
237
+ | `keyframe_exp` | u8 | Name block size. `0` means the whole name list is a single block. Any other value `k` means each block holds `I = 2^k` names. See [Section 7.3](#73-name-blocks). |
238
+
239
+ The `version` field carries two numbers: its low 4 bits are the format
240
+ version within a kind, and the remaining high bits are the **kind**,
241
+ which distinguishes the different files that share the `CGEODATA`
242
+ signature. The kinds are:
243
+
244
+ | Kind | Value of `version` | File |
245
+ |------|--------------------|------|
246
+ | `0` | `0` to `15` | A CGEODATA file as described by Sections 4 to 9. |
247
+ | `1` | `16` to `31` | A text search index derived from a kind `0` file ([Appendix B](#appendix-b-text-search-index)). |
248
+ | `2` | `32` to `47` | A place location index derived from a kind `0` file ([Appendix C](#appendix-c-place-location-index)). |
249
+
250
+ Other kinds are reserved. Kinds `1` and up are sidecar files: each is
251
+ derived from one kind `0` file, is regenerated rather than edited, and
252
+ has its own layout after the `version` field. Whether a file is a
253
+ sidecar is fixed by its kind, not by its name or location.
254
+
255
+ Readers MUST reject a file whose signature does not match, whose kind
256
+ is not the kind they expect, or whose version they do not implement.
257
+ Version `0` of any kind is a pre-release version: files written under
258
+ this document carry no compatibility promise once the version number
259
+ changes.
260
+
261
+ Versions `0`, `1` and `2` of kind `0` differ only in how a chunk is
262
+ stored. Version `0` stored every record's Morton code, which version `1`
263
+ derives from the depths ([Section 8.6](#86-version-0-chunks)). Version
264
+ `2` keeps version `1`'s records but stores them range coded instead of
265
+ in a zlib stream ([Section 8.7](#87-version-2-chunks)). A reader MAY read
266
+ all three.
267
+
268
+ Constraints:
269
+
270
+ - `max_depth` MUST be at most `26`, so that a Morton code (`2 × D` bits)
271
+ fits in 52 bits and is an exact integer in JavaScript.
272
+ - `width_exp` and `height_exp` MUST each be at most `15`. Larger values
273
+ are reserved.
274
+
275
+ Choosing the grid sizes is discussed in
276
+ [Section 10](#10-encoder-considerations).
277
+
278
+ ## 6. Directory
279
+
280
+ ### 6.1. Chunk Grid
281
+
282
+ The chunk grid divides the world into `W` columns and `H` rows of equal
283
+ angular size. Column `c` (`0 <= c < W`) covers longitudes
284
+ `[-180 + c × 360 / W, -180 + (c + 1) × 360 / W)`. Row `r` (`0 <= r < H`)
285
+ covers latitudes `[-90 + r × 180 / H, -90 + (r + 1) × 180 / H)`. Row `0`
286
+ is the southernmost row; the origin of the grid is the south-west corner
287
+ of the world at `(lat -90, lon -180)`.
288
+
289
+ Chunks are numbered in row-major order: chunk index `i = r × W + c`.
290
+ This is the order of both the chunk length table and the stored chunks.
291
+
292
+ For example, with `width_exp = 6` (`W = 64`) each column is `5.625°`
293
+ wide: column `0` covers `[-180, -174.375)`, column `1` covers
294
+ `[-174.375, -168.75)`, and so on.
295
+
296
+ ### 6.2. Layout
297
+
298
+ Immediately after the header:
299
+
300
+ | Field | Type | Description |
301
+ |----------------------|-------------------|-------------|
302
+ | `place_table_length` | varint | Byte length of the entire place table ([Section 7](#7-place-table)), including its uncompressed prefix. |
303
+ | `chunk_lengths` | `W × H` varints | Entry `i` is the byte length of the compressed block for chunk `i`. `0` means chunk `i` is empty: no bytes are stored for it, and every coordinate inside it resolves to unknown. |
304
+
305
+ Entries are plain lengths, not deltas and not offsets.
306
+
307
+ ### 6.3. Locating a Chunk
308
+
309
+ Let `chunks_start` be the file offset of the first byte after the place
310
+ table, that is, the offset of the end of `chunk_lengths` plus
311
+ `place_table_length`. Then the compressed block for chunk `i` occupies
312
+
313
+ ```
314
+ offset(i) = chunks_start + sum(chunk_lengths[0 .. i-1])
315
+ length(i) = chunk_lengths[i]
316
+ ```
317
+
318
+ Readers SHOULD compute the prefix sums once when loading the directory,
319
+ so that locating a chunk is an array index. The directory alone is
320
+ enough to locate any chunk; no chunk needs to be decompressed to find
321
+ another.
322
+
323
+ The last chunk's length is recorded like any other. Because each chunk
324
+ is a self-contained zlib stream, a reader could inflate it without
325
+ knowing its length, but the recorded length lets a reader bound the read
326
+ and verify that the file is complete.
327
+
328
+ ## 7. Place Table
329
+
330
+ The place table is the list of all countries, regions, and cities the
331
+ file knows about, their names, and the parent of each region and city.
332
+ It is used to turn the identifier found by a spatial lookup into names,
333
+ and to support text search and listing.
334
+
335
+ ### 7.1. Identifiers and Hierarchy
336
+
337
+ The hierarchy has exactly three levels: countries contain regions, and
338
+ regions contain cities. Places are numbered in one shared identifier
339
+ space:
340
+
341
+ - IDs `0 .. C-1` are the `C` countries.
342
+ - IDs `C .. C+R-1` are the `R` regions, grouped by country: all regions
343
+ of country `0` first, then all regions of country `1`, and so on.
344
+ - IDs `C+R .. N-1` are the cities, grouped by region in the same way.
345
+ `N = C + R + (number of cities)` is the total number of places.
346
+
347
+ An identifier denotes exactly one place; a value used for a country is
348
+ never also used for a region or city. Chunk palettes
349
+ ([Section 8.3](#83-palette)) MAY reference any place, at any level: a
350
+ cell whose most specific known place is a region resolves to that
351
+ region.
352
+
353
+ The grouping order is what makes the hierarchy cheap to store: instead
354
+ of a parent pointer per place, the table stores only how many children
355
+ each parent has, and readers recover parents from prefix sums. A useful
356
+ side effect is that a search that stops after a limited number of hits
357
+ naturally reports countries before regions before cities.
358
+
359
+ ### 7.2. Layout
360
+
361
+ | Field | Type | Description |
362
+ |---------------------|----------------------|-------------|
363
+ | `country_count` | varint | `C`, the number of countries. |
364
+ | `region_counts` | `C` varints | Entry `j` is the number of regions belonging to country `j`. `R` is the sum of all entries. |
365
+ | `city_counts` | `R` varints | Entry `j` is the number of cities belonging to region `j` (region index, not ID). The number of cities is the sum of all entries. |
366
+ | `block_lengths` | `K - 1` varints | Entry `b` is the byte length of name block `b`, for `0 <= b < K-1`. `K` is defined in Section 7.3. |
367
+ | `name_blocks` | `K` compressed blocks | The name list, in ID order, split into blocks as described in Section 7.3. |
368
+
369
+ The four count fields are uncompressed and are expected to be read once
370
+ and kept in memory. A country's region count or a region's city count
371
+ MAY be `0`.
372
+
373
+ ### 7.3. Name Blocks
374
+
375
+ The name list is the concatenation, in ID order, of every place's name
376
+ entry ([Section 7.4](#74-name-entries)), each followed by a `NUL` byte.
377
+ It is split into `K` blocks of `I` consecutive entries each (the last
378
+ block MAY be shorter), where
379
+
380
+ ```
381
+ I = 2^keyframe_exp (if keyframe_exp != 0)
382
+ K = ceil(N / I) (if keyframe_exp != 0)
383
+ K = 1 (if keyframe_exp == 0)
384
+ ```
385
+
386
+ A file with no places (`N = 0`) has `K = 0` and no name blocks.
387
+
388
+ Block `b` holds the entries with IDs `b × I .. min((b + 1) × I, N) - 1`.
389
+ A block boundary MAY fall anywhere, including between a country and a
390
+ region. Each block is compressed separately as one compressed block
391
+ ([Section 3.5](#35-compressed-blocks)).
392
+
393
+ Block `b` starts at
394
+
395
+ ```
396
+ names_start + sum(block_lengths[0 .. b-1])
397
+ ```
398
+
399
+ where `names_start` is the offset of the first byte after
400
+ `block_lengths`. The length of the last block is not stored; it extends
401
+ to the end of the place table, so its length is `place_table_length`
402
+ minus the number of bytes consumed by everything before it.
403
+
404
+ The blocks act as keyframes for random access: to recover the name of
405
+ place `id`, a reader inflates only block `floor(id / I)` and skips
406
+ `id mod I` `NUL`-terminated entries. A smaller `I` gives cheaper random
407
+ access; a larger `I` gives better compression, since zlib finds more
408
+ repetition in a larger block, and a shorter `block_lengths` list.
409
+
410
+ `keyframe_exp = 7` (blocks of 128 names) is RECOMMENDED. Measured on the
411
+ worldwide file (about 319,000 places), with a reader that opens the file
412
+ afresh for every operation so that no name block is cached, which is
413
+ the situation of a reader that is queried only occasionally:
414
+
415
+ | `keyframe_exp` | Place table | Resolving one place | Scanning all names |
416
+ |----------------|-------------|---------------------|--------------------|
417
+ | `13` | 1.64 MB | 4.9 ms | 134 ms |
418
+ | `11` | 1.70 MB | 1.7 ms | 142 ms |
419
+ | `9` | 1.82 MB | 0.9 ms | 141 ms |
420
+ | `7` | 2.05 MB | 0.7 ms | 152 ms |
421
+ | `5` | 2.53 MB | 1.4 ms | 210 ms |
422
+
423
+ "Resolving one place" is a place and its parents' names, as every
424
+ lookup ([Section 9](#9-lookup-procedure)) that finds a place needs.
425
+ Name access is random in nearly every use: a lookup needs up to three
426
+ names from anywhere in the table, and a search confirms candidates
427
+ spread across it ([Section B.9](#b9-query-procedure)), so every
428
+ operation other than a full scan pays for one block per distinct name
429
+ it touches, and a smaller block is directly cheaper. Below `7` the
430
+ fixed costs take over: a reader parses `K - 1` block lengths when it
431
+ opens the file, and each block carries its own zlib framing, so both
432
+ opening the file and a full scan get slower. The place table grows by
433
+ a quarter from `13` to `7`, which is small beside the chunks at any
434
+ useful `max_depth`.
435
+
436
+ ### 7.4. Name Entries
437
+
438
+ A name entry is one or more names separated by `|` (`0x7C`), interpreted
439
+ by position:
440
+
441
+ 1. The first field is the local name, as the place is called in its own
442
+ language, for example `Nederland`. It MUST NOT be empty.
443
+ 2. The second field is the international (English) name, for example
444
+ `The Netherlands`. It MAY be empty or absent, meaning the
445
+ international name is the same as the local name.
446
+ 3. Any further fields are alternative names or spellings, useful for
447
+ search, for example the historical or transliterated names.
448
+
449
+ Writers SHOULD omit trailing empty fields, so a place with a single name
450
+ is stored as `Amsterdam`, not `Amsterdam|`. Fields MUST NOT contain `|`
451
+ or `NUL`; there is no escape mechanism. A reader that displays a place
452
+ SHOULD show the local name, and a search SHOULD match against every
453
+ field.
454
+
455
+ Examples:
456
+
457
+ ```
458
+ Nederland|The Netherlands
459
+ Den Haag|The Hague|'s-Gravenhage
460
+ Amsterdam
461
+ ```
462
+
463
+ ### 7.5. Resolving an Identifier
464
+
465
+ Given the counts of Section 7.2, a reader classifies `id` as follows:
466
+
467
+ - If `id < C`, it is country `id`.
468
+ - Otherwise, if `id < C + R`, it is the region with region index
469
+ `j = id - C`. Its country is the largest `c` such that
470
+ `sum(region_counts[0 .. c-1]) <= j`.
471
+ - Otherwise it is the city with city index `j = id - C - R`. Its region
472
+ index is the largest `r` such that `sum(city_counts[0 .. r-1]) <= j`,
473
+ and its country follows from the region as above.
474
+
475
+ Readers SHOULD precompute the two prefix-sum arrays at load time, after
476
+ which both steps are a binary search. Readers MUST reject an `id` that
477
+ is not less than `N`.
478
+
479
+ ## 8. Chunks
480
+
481
+ Each non-empty chunk stores the spatial index for its area as a single
482
+ compressed block ([Section 3.5](#35-compressed-blocks)). This section
483
+ describes the inflated content.
484
+
485
+ ### 8.1. Cell Grid and Morton Codes
486
+
487
+ Inside a chunk, a quadtree of depth `D = max_depth` subdivides the chunk
488
+ into `2^D × 2^D` cells of equal angular size. A cell is addressed by its
489
+ column `x` and row `y`, each in `[0, 2^D)`, counted from the chunk's
490
+ south-west corner: `x` increases eastward and `y` increases northward.
491
+
492
+ The full-precision Morton code of cell `(x, y)` is the `2 × D`-bit
493
+ integer obtained by interleaving the bits of `y` and `x`, most
494
+ significant first, with the `y` bit placed above the `x` bit in every
495
+ pair:
496
+
497
+ ```
498
+ code = 0
499
+ for i from D-1 down to 0:
500
+ code = (code << 1) | ((y >> i) & 1)
501
+ code = (code << 1) | ((x >> i) & 1)
502
+ ```
503
+
504
+ Equivalently, reading the code two bits at a time from the top selects a
505
+ quadrant at each level: `00` south-west, `01` south-east, `10`
506
+ north-west, `11` north-east.
507
+
508
+ A cell at depth `d < D` is the union of the `4^(D-d)` full-precision
509
+ cells whose codes share its top `2 × d` bits. Its **stored code** is the
510
+ smallest of those codes: the `2 × d` path bits followed by
511
+ `2 × (D - d)` zero bits. Consequently the stored code of a cell is the
512
+ minimum full-precision code of any point inside it, which is the
513
+ invariant the lookup in [Section 9](#9-lookup-procedure) depends on.
514
+
515
+ Codes are chunk-local. Cell `(0, 0)` is the chunk's own south-west
516
+ corner, not the world's. This keeps codes small.
517
+
518
+ For `D = 2` the sixteen full-precision codes are laid out as follows
519
+ (north is up):
520
+
521
+ ```
522
+ y=3 | 10 11 14 15
523
+ y=2 | 8 9 12 13
524
+ y=1 | 2 3 6 7
525
+ y=0 | 0 1 4 5
526
+ +----------------
527
+ x=0 x=1 x=2 x=3
528
+ ```
529
+
530
+ ### 8.2. Layout
531
+
532
+ | Field | Type | Description |
533
+ |-------------------|----------------------------|-------------|
534
+ | `palette_count` | varint | `P`, the number of palette entries. |
535
+ | `palette` | `P` varints, delta-coded | Place IDs referenced by this chunk, strictly increasing ([Section 8.3](#83-palette)). |
536
+ | `record_count` | varint | `M`, the number of records. |
537
+ | `depths` | `M` u8 | Depth `d` of each record, in Morton order. |
538
+ | `palette_indices` | `M` × `S` bytes | Palette index of each record, in Morton order, as unsigned little-endian integers of `S` bytes. |
539
+
540
+ The two per-record arrays are stored one after the other rather than
541
+ interleaved per record. Grouping same-typed values together lets zlib
542
+ find far more repetition; on the prototype data this columnar layout
543
+ plus delta coding reduced the index about twelvefold compared with
544
+ fixed 8-byte records.
545
+
546
+ A record's Morton code is not stored: the records tile the chunk in
547
+ Morton order, so each one starts where the one before it ends
548
+ ([Section 8.4](#84-records)). Both arrays are fixed width, so the length
549
+ of the block follows from `P` and `M`.
550
+
551
+ The inflated block MUST contain exactly these fields and nothing else:
552
+ after `palette_indices` the block ends.
553
+
554
+ ### 8.3. Palette
555
+
556
+ The palette lists every place ID referenced by the chunk's records, in
557
+ strictly increasing order, delta-coded ([Section 3.3](#33-delta-coded-lists)).
558
+ The first stored value is the first ID itself (its delta from `0`), so an
559
+ ID of `0`, the first country, can be referenced.
560
+
561
+ Records refer to the palette by a **local index** in `[0, P]`:
562
+
563
+ - Index `0` means "no place". A record with index `0` resolves to
564
+ unknown, exactly as if no record covered the cell.
565
+ - Index `k` for `1 <= k <= P` refers to `palette[k - 1]`.
566
+
567
+ The index width `S` is derived from `P`:
568
+
569
+ | `P` | `S` |
570
+ |-------------------------|---------|
571
+ | `P <= 255` | 1 byte |
572
+ | `256 <= P <= 65535` | 2 bytes |
573
+ | `65536 <= P <= 2^24-1` | 3 bytes |
574
+ | otherwise | 4 bytes |
575
+
576
+ Most chunks are expected to reference a few dozen places at most and to
577
+ use 1-byte indices.
578
+
579
+ Every palette entry MUST be a valid place ID, that is, less than `N`.
580
+
581
+ ### 8.4. Records
582
+
583
+ Record `j` is the triple `(codes[j], depths[j], palette_indices[j])`.
584
+ It states that the cell at depth `depths[j]` whose stored code is
585
+ `codes[j]` is attributed to the place selected by `palette_indices[j]`.
586
+
587
+ A cell denoted by `(code, d)` covers the full-precision code range
588
+ `[code, code + 4^(D-d))`. The records cover the chunk from its first
589
+ full-precision cell on, without gaps, so each code is where the record
590
+ before it ends:
591
+
592
+ ```
593
+ codes[0] = 0
594
+ codes[j+1] = codes[j] + 4^(D - depths[j])
595
+ ```
596
+
597
+ An empty area between two places is covered by records with palette
598
+ index `0`. The records MAY end before the chunk does: the cells from
599
+ `codes[M-1] + 4^(D - depths[M-1])` up to `4^D` have no record and resolve
600
+ to unknown. A chunk with no place at all need not be stored
601
+ ([Section 6.2](#62-layout)).
602
+
603
+ ### 8.5. Invariants
604
+
605
+ A chunk MUST satisfy all of the following. Readers MAY verify them at
606
+ load time and MUST NOT rely on undefined behaviour if they do not.
607
+
608
+ 1. `0 <= depths[j] <= D` for every record.
609
+ 2. The low `2 × (D - depths[j])` bits of `codes[j]` are zero (the code
610
+ is a stored code as defined in Section 8.1).
611
+ 3. The records end within the chunk:
612
+ `codes[M-1] + 4^(D - depths[M-1]) <= 4^D`.
613
+ 4. Every palette index is at most `P`.
614
+
615
+ Codes are then strictly increasing, every code is less than `4^D`, and
616
+ cells do not overlap, by construction.
617
+
618
+ ### 8.6. Version 0 Chunks
619
+
620
+ In a version `0` file ([Section 5](#5-header)), a chunk stores every
621
+ record's code, between `record_count` and `depths`:
622
+
623
+ | Field | Type | Description |
624
+ |-------------------|----------------------------|-------------|
625
+ | `palette_count` | varint | As in Section 8.2. |
626
+ | `palette` | `P` varints, delta-coded | As in Section 8.2. |
627
+ | `record_count` | varint | As in Section 8.2. |
628
+ | `codes_length` | varint | Byte length of `codes`. |
629
+ | `codes` | `M` varints, delta-coded | Stored Morton codes, strictly increasing. |
630
+ | `depths` | `M` u8 | As in Section 8.2. |
631
+ | `palette_indices` | `M` × `S` bytes | As in Section 8.2. |
632
+
633
+ The records need not tile the chunk: a writer could leave out any empty
634
+ cell, not only those after the last record, and a coordinate in such a
635
+ gap resolves to unknown. Invariants 1, 2 and 4 of
636
+ [Section 8.5](#85-invariants) apply, and invariant 3 is replaced by:
637
+
638
+ - Codes are strictly increasing, `codes[j] < codes[j+1]`, and cells do
639
+ not overlap, `codes[j] + 4^(D - depths[j]) <= codes[j+1]`.
640
+ - Every code is less than `4^D`.
641
+
642
+ Version `1` dropped the codes because they were nearly all redundant.
643
+ A writer's records hardly ever leave a gap, and where none is left, a
644
+ code delta is the size of the record before it, `4^(D - depths[j])`.
645
+ zlib, which sees the codes and the depths as separate columns, did not
646
+ find that out. In the worldwide file, 1.66 million gaps among 106.4
647
+ million records took 3.77 million index-`0` records (3.5% more records)
648
+ to fill, and the chunks went from 62.2 MB to 45.6 MB (-26.7%), with the
649
+ same cell for every place.
650
+
651
+ ### 8.7. Version 2 Chunks
652
+
653
+ In a version `2` file ([Section 5](#5-header)), a chunk's records are
654
+ those of a version `1` chunk ([Sections 8.4](#84-records) and
655
+ [8.5](#85-invariants)): they tile the chunk from code `0` in Morton order,
656
+ and MAY end before the chunk does. Only their storage differs. The block
657
+ is not a zlib stream:
658
+
659
+ | Field | Type | Description |
660
+ |-------------------|----------------------------|-------------|
661
+ | `palette_count` | varint | As in Section 8.2, and below `2^26`. |
662
+ | `palette` | `P` varints, delta-coded | As in Section 8.2. |
663
+ | `record_count` | varint | As in Section 8.2. |
664
+ | `stream` | bytes | The rest of the block: the records' depths and palette indices, range coded as described below. |
665
+
666
+ The stream codes the chunk's quadtree as a series of binary decisions:
667
+ whether each node splits, and, for each leaf, which palette index it has.
668
+ Every decision is made with an adaptive probability chosen by a
669
+ **context** from what was already decoded: chiefly the records to the
670
+ west and south of the node, which in Morton order always come first.
671
+ Neighbouring cells usually belong to the same place, so most decisions
672
+ are nearly certain and cost a small fraction of a bit.
673
+
674
+ #### 8.7.1. Range Decoder
675
+
676
+ The decoder keeps two unsigned 32-bit integers, `range` and `code`, and a
677
+ position `pos` in `stream`. Each probability `p` is an integer in
678
+ `[1, 4095]`, the chance out of `4096` that a decision is `0`; every
679
+ probability starts at `2048`.
680
+
681
+ `stream[0]` MUST be `0`. `code` starts as `stream[1..4]` read as a
682
+ big-endian integer, and MUST NOT be `0xFFFFFFFF`; `range` starts as
683
+ `0xFFFFFFFF` and `pos` as `5`. A decision with probability `p` is decoded
684
+ as follows, and `p` is updated in place:
685
+
686
+ ```
687
+ bound = (range >> 12) × p
688
+ if code < bound:
689
+ range = bound
690
+ p = p + ((4096 - p) >> 4)
691
+ bit = 0
692
+ else:
693
+ code = code - bound
694
+ range = range - bound
695
+ p = p - (p >> 4)
696
+ bit = 1
697
+ while range < 2^24:
698
+ range = range × 256
699
+ code = code × 256 + stream[pos] # reading past the end is an error
700
+ pos = pos + 1
701
+ ```
702
+
703
+ After the last record, `pos` MUST equal the length of `stream`. This is
704
+ LZMA's range coder [LZMA] with 12-bit probabilities that adapt by a
705
+ sixteenth each time. The matching encoder (informative):
706
+
707
+ ```
708
+ low = 0 (at least 33 bits), range = 0xFFFFFFFF, cache = 0, pending = 1
709
+
710
+ encode(bit, p):
711
+ bound = (range >> 12) × p
712
+ if bit == 0: range = bound; p = p + ((4096 - p) >> 4)
713
+ else: low = low + bound; range = range - bound; p = p - (p >> 4)
714
+ while range < 2^24: range = range × 256; shift_low()
715
+
716
+ shift_low():
717
+ if low < 0xFF000000 or low >= 2^32:
718
+ carry = low >> 32
719
+ emit (cache + carry) & 0xFF, then pending - 1 bytes of (0xFF + carry) & 0xFF
720
+ pending = 0
721
+ cache = (low >> 24) & 0xFF
722
+ pending = pending + 1
723
+ low = (low & 0x00FFFFFF) × 256
724
+
725
+ finish(): shift_low() five times.
726
+ ```
727
+
728
+ Its first byte is always `0`, and the decoder then reads exactly the
729
+ bytes it wrote.
730
+
731
+ #### 8.7.2. Nodes and Neighbours
732
+
733
+ A node is a cell of the chunk's quadtree: its depth `d` and its south-west
734
+ corner `(x, y)`, in full-precision cells ([Section 8.1](#81-cell-grid-and-morton-codes)).
735
+ Nodes are visited in pre-order from the root `(d = 0, x = 0, y = 0)`. A
736
+ node at depth `d < D` first decodes a **split** decision
737
+ ([Section 8.7.3](#873-contexts)): `1` visits its four children of depth
738
+ `d + 1` in Morton order, south-west `(x, y)`, south-east `(x + h, y)`,
739
+ north-west `(x, y + h)` and north-east `(x + h, y + h)` with
740
+ `h = 2^(D - d - 1)`; `0` makes it a leaf. A node at depth `D` is a leaf
741
+ without a decision. Each leaf is the next record: its depth is `d`, its
742
+ code is where the record before it ends ([Section 8.4](#84-records)), and
743
+ its palette index is decoded as [Section 8.7.4](#874-palette-indices)
744
+ describes. Decoding stops after `record_count` records, wherever the
745
+ traversal is.
746
+
747
+ A node's **west neighbour** is the record that contains the
748
+ full-precision cell `(x - 1, y)`, and its **south neighbour** the one
749
+ that contains `(x, y - 1)`. There is none when `x = 0` (respectively
750
+ `y = 0`): neighbours never come from another chunk. Both cells have
751
+ lower Morton codes than `(x, y)` and so were decoded before the node. A
752
+ decoder can find them by remembering, for every row and every column of
753
+ full-precision cells, the last record decoded in it: in Morton order the
754
+ last record in row `y` before `(x, y)` is the one at `(x - 1, y)`, and
755
+ likewise for columns.
756
+
757
+ A neighbour's **category** relative to a node at depth `d` is `0` when
758
+ there is no neighbour, `1` when its record's depth is at most `d`, `2`
759
+ when it is `d + 1`, and `3` when it is deeper.
760
+
761
+ #### 8.7.3. Contexts
762
+
763
+ There are five tables of probabilities, each indexed by a context:
764
+
765
+ | Table | Entries | Used for |
766
+ |---------------|---------|----------|
767
+ | `split` | 256 | split decisions, at `16 × d + 4 × cw + cs` |
768
+ | `same_west` | 544 | "the index is the west neighbour's", at `c` |
769
+ | `same_south` | 544 | "the index is the south neighbour's", at `c` |
770
+ | `rank_length` | 128 | the unary part of a rank ([Section 8.7.4](#874-palette-indices)) |
771
+ | `rank_bits` | 1024 | the binary part of a rank |
772
+
773
+ `cw` and `cs` are the west and south neighbours' categories. For a leaf,
774
+ let `w` and `s` be the west and south neighbours' palette indices, or
775
+ `-1` for a missing one, and `prev` the previous record's palette index,
776
+ or `-1` for the first record. Then
777
+
778
+ ```
779
+ c = 4 × (8 × d + 4 × [w = s] + 2 × [prev = w] + [prev = s]) + cw
780
+ ```
781
+
782
+ where `[...]` is `1` when the comparison holds and `0` otherwise, and
783
+ `-1` equals `-1`.
784
+
785
+ #### 8.7.4. Palette Indices
786
+
787
+ The decoder keeps a **move-to-front list** of the palette indices
788
+ `0` to `P`, initially in that order. A leaf's palette index `v` is
789
+ decoded as follows:
790
+
791
+ 1. If there is a west neighbour, a decision in `same_west[c]`: `1` means
792
+ `v = w`.
793
+ 2. Otherwise, or if that decision was `0`: if there is a south
794
+ neighbour and `s != w`, a decision in `same_south[c]`: `1` means
795
+ `v = s`.
796
+ 3. Otherwise, a **rank** `r`: `v` is the entry of the move-to-front list
797
+ that has `r` entries before it, not counting entries equal to `w` or
798
+ `s`. `r + 1` is coded in Elias gamma: let `a` be `1` if there is a
799
+ west neighbour plus `2` if there is a south neighbour. Decisions in
800
+ `rank_length[32 × a + k]`, for `k = 0, 1, ...`, are `1` until one is
801
+ `0`; their number of `1`s is `n`, and MUST be below `32`. Then `n`
802
+ decisions in `rank_bits[32 × n + k]`, for `k = n - 1` down to `0`,
803
+ are the bits of `r + 1` below its leading `1`, most significant
804
+ first. The list MUST have such an entry.
805
+
806
+ Then `v` is moved to the front of the list.
807
+
808
+ #### 8.7.5. Bounds and Errors
809
+
810
+ A decoder MUST reject a block where `record_count` exceeds `4^D` (more
811
+ records than cells), or exceeds `2048` times the length of `stream`, and
812
+ MUST check both before allocating for the records. No stream reaches the
813
+ second bound: every record takes at least one decision, a decision
814
+ takes at least `log2(4096 / 4081)` bits, as no probability passes
815
+ `4081` or drops below `15`, so a byte codes at most about 1500 records.
816
+
817
+ It MUST also reject a block whose traversal ends (every node visited)
818
+ before `record_count` records, and any of the conditions marked MUST in
819
+ Sections 8.7.1 and 8.7.4. Every record is valid by construction: its
820
+ depth is at most `D`, it is aligned, it ends within the chunk, and its
821
+ palette index is at most `P`.
822
+
823
+ #### 8.7.6. Design Notes
824
+
825
+ This section is informative.
826
+
827
+ The range coder replaced zlib for chunks because the data has structure
828
+ a general-purpose compressor does not see. A version `1` chunk stores
829
+ each depth in a byte, though the depths are just a pre-order listing of
830
+ the quadtree's split flags, which are well predicted by the neighbours'
831
+ depths. Its palette indices are well predicted by the west and south
832
+ neighbours, which in Morton order are not usually the previous record:
833
+ in the worldwide file, 74% of records have their west neighbour's index
834
+ and 19% their south neighbour's, which zlib, looking at one byte column,
835
+ cannot exploit. Measured on the worldwide build (7,608 chunks,
836
+ 110 million records), the chunks went from 45.6 MB as version `1` to
837
+ 18.5 MB (−59.5%), and the file from 47.6 MB to 20.5 MB.
838
+
839
+ The cost is decoding speed: about 2.5 binary decisions per record, each
840
+ data-dependent, make a chunk about 4 times as slow to decode as to
841
+ inflate and parse in version `1`. Encoding is faster than zlib's highest
842
+ level. Other layouts were measured on the same file: zlib over split
843
+ flags and neighbour-predicted symbols gave 30.2 MB, and Zopfli, a better
844
+ deflate encoder for version `1` unchanged, about 37.4 MB.
845
+
846
+ ## 9. Lookup Procedure
847
+
848
+ To resolve a coordinate `(lat, lon)` to a place ID, a reader performs the
849
+ following steps. `W`, `H`, and `D` come from the header.
850
+
851
+ 1. **Validate.** If `lat` or `lon` is outside the ranges of
852
+ [Section 2.3](#23-coordinate-system), fail.
853
+ 2. **Compute global cell coordinates.** Let `NX = W × 2^D` and
854
+ `NY = H × 2^D` be the total number of full-precision cells across the
855
+ world in each direction.
856
+
857
+ ```
858
+ gx = floor((lon + 180) / 360 × NX)
859
+ gy = floor((lat + 90) / 180 × NY)
860
+ ```
861
+
862
+ Because floating-point rounding can push a value just below the upper
863
+ bound onto it, readers MUST clamp `gx` to `[0, NX-1]` and `gy` to
864
+ `[0, NY-1]`.
865
+ 3. **Split into chunk and local cell.** `c = gx >> D`, `r = gy >> D`,
866
+ `x = gx & (2^D - 1)`, `y = gy & (2^D - 1)`, and the chunk index is
867
+ `i = r × W + c`. Computing `gx` and `gy` once and splitting them, rather
868
+ than computing the chunk and the local cell with separate divisions,
869
+ avoids inconsistent rounding between the two.
870
+ 4. **Fetch the chunk.** If `chunk_lengths[i]` is `0`, the result is
871
+ unknown. Otherwise read `length(i)` bytes at `offset(i)`
872
+ ([Section 6.3](#63-locating-a-chunk)) and inflate them (in a version
873
+ `2` file, decode them per [Section 8.7](#87-version-2-chunks)), and
874
+ compute the records' codes ([Section 8.4](#84-records)). Readers
875
+ SHOULD cache decoded chunks with their codes.
876
+ 5. **Compute the query code** `q` from `(x, y)` with the procedure of
877
+ [Section 8.1](#81-cell-grid-and-morton-codes).
878
+ 6. **Binary search.** Find the largest `j` such that `codes[j] <= q`
879
+ (`bisect_right(codes, q) - 1` in Python terms). If no such `j` exists,
880
+ the result is unknown.
881
+ 7. **Verify containment.** Let `shift = 2 × (D - depths[j])`. If
882
+ `(q >> shift) != (codes[j] >> shift)`, the point lies after the last
883
+ record (or, in a version `0` file, in a gap between records) and the
884
+ result is unknown.
885
+ 8. **Resolve the palette index.** Let `k = palette_indices[j]`. If `k` is
886
+ `0`, the result is unknown. Otherwise the result is `palette[k - 1]`.
887
+
888
+ Step 6 is correct because of the invariants of
889
+ [Section 8.5](#85-invariants): every stored code is the minimum code of
890
+ its cell, cells do not overlap, and codes are sorted, so the cell
891
+ containing `q`, if any, is the one with the largest stored code not
892
+ exceeding `q`. Step 7 is required because the records may end before the
893
+ chunk does.
894
+
895
+ To present the result, the reader resolves the ID to its parents
896
+ ([Section 7.5](#75-resolving-an-identifier)) and recovers the names from
897
+ the appropriate name blocks ([Section 7.3](#73-name-blocks)).
898
+
899
+ ## 10. Encoder Considerations
900
+
901
+ This section is informative.
902
+
903
+ **Chunk grid size.** More chunks mean that each lookup inflates a smaller
904
+ block and that codes are shorter, at the cost of a larger directory and
905
+ some per-chunk overhead (zlib framing and a palette per chunk). Chunks
906
+ over open ocean cost only their `0` length entry. `width_exp = height_exp + 1`
907
+ gives chunks that are square in degrees; any other ratio gives
908
+ rectangular chunks and cells, which is permitted.
909
+
910
+ **Maximum depth.** `D` together with the chunk grid fixes the finest
911
+ resolution: a full-precision cell is `360 / (W × 2^D)` degrees of
912
+ longitude by `180 / (H × 2^D)` degrees of latitude. The prototype found
913
+ that forcing every ambiguous cell down to a 10 m floor produced far more
914
+ records than the size budget allowed, while stopping at roughly 300 m
915
+ and attributing the remaining ambiguous cells to the candidate with the
916
+ largest share of the cell's area gave good results for geotagging.
917
+
918
+ A deep `D` makes lookups slower, not just files smaller: a chunk is one
919
+ zlib block, which a lookup inflates whole, and it spans up to `4^D`
920
+ cells -- already over four billion at `D = 16`. Finer cells should come
921
+ from a bigger chunk grid instead. The reference reader therefore
922
+ rejects files with `D` above `16`, where every Morton code still fits in
923
+ an unsigned 32-bit integer (`4^16 = 2^32`); a writer SHOULD stay at or
924
+ below it. With a `128 × 128` chunk grid, `D = 16` is a cell about 5 m
925
+ wide at the equator. Deeper files are valid, but only suit transfer or
926
+ archiving, where a decoder can stream through each chunk.
927
+
928
+ **Building records.** The intended construction is recursive: starting
929
+ from the chunk as a depth-`0` cell, stop and emit a record when no place
930
+ touches the cell (with palette index `0`), or when exactly one place
931
+ fully contains it; otherwise subdivide, and at depth `D` pick one
932
+ candidate. When several places fully contain a cell (nested
933
+ administrative levels), prefer the smallest.
934
+
935
+ **Empty cells.** An empty area between two records is best written as
936
+ the fewest index-`0` records that cover it: each the largest cell that
937
+ starts where the one before it ends and does not reach past the area.
938
+ Four empty siblings make one empty parent, as they would in the
939
+ recursive construction. Empty cells after the last record need no
940
+ record at all.
941
+
942
+ **Keyframe interval.** See [Section 7.3](#73-name-blocks).
943
+
944
+ **Compression.** Versions `0` and `1` chose zlib over zstd or brotli
945
+ because it is a zero-dependency built-in in Node.js and browsers. The
946
+ columnar and delta-coded layout captures most of the gain regardless of
947
+ the compressor; on the prototype, zstd and brotli were only 10–20%
948
+ smaller. Writers of those versions SHOULD use the highest zlib
949
+ compression level; compression is a one-time cost. Version `2`'s range
950
+ coder ([Section 8.7](#87-version-2-chunks)) is a model of the data, not
951
+ a general-purpose compressor, and needs no library; see
952
+ [Section 8.7.6](#876-design-notes) for what it gains and costs.
953
+
954
+ ## 11. Robustness and Security Considerations
955
+
956
+ A CGEODATA file may come from an untrusted source. Readers MUST NOT
957
+ assume that a file is well formed.
958
+
959
+ - Readers MUST verify the signature, kind, and version before
960
+ interpreting any other field.
961
+ - Readers MUST check that `place_table_length`, every chunk offset, and
962
+ every chunk length lie within the file before reading.
963
+ - Readers MUST bound the inflated size of every compressed block. A
964
+ chunk's inflated size is at most a small multiple of what its counts
965
+ imply; a reader SHOULD inflate with an explicit output limit and reject
966
+ a block that exceeds it, to defend against decompression bombs.
967
+ - Readers MUST check that the inflated chunk contains exactly the bytes
968
+ its counts require, that every depth is at most `D`, that the records
969
+ end within the chunk, that every palette index is at most `P`, and
970
+ that every palette entry is less than `N`. Readers MAY additionally
971
+ verify the alignment invariant of [Section 8.5](#85-invariants), and
972
+ in a version `0` file the ordering and non-overlap invariants of
973
+ [Section 8.6](#86-version-0-chunks).
974
+ - In a version `2` file, readers MUST check [Section 8.7.5](#875-bounds-and-errors)'s
975
+ bounds on `record_count` before allocating for it, and reject a stream
976
+ that runs past the end of its block or ends before it. The records'
977
+ depths, codes and palette indices are valid by construction.
978
+ - Readers MUST treat the attribution text and place names as untrusted
979
+ text. Where they are rendered as Markdown or HTML, they MUST be
980
+ sanitised.
981
+ - Varints MUST be rejected when longer than 8 bytes, so that a malformed
982
+ file cannot cause unbounded loops or values beyond `2^53`.
983
+
984
+ ## 12. Open Issues
985
+
986
+ The following are known gaps or unresolved decisions in version `2`.
987
+
988
+ 1. **Latitude scaling.** Because the grid is equirectangular, cells
989
+ shrink in east-west extent towards the poles. A per-row scaling
990
+ factor, or fewer columns at high latitudes, would keep cells closer to
991
+ square on the ground. Not addressed in this version.
992
+ 2. **Representative points are derived, not stored.** A place search
993
+ that returns a location for each hit (as Immich's `searchPlaces`
994
+ does) needs a representative point per place. The place table has no
995
+ such field; the point is derived from the chunks
996
+ ([Section C.3](#c3-representative-cell)) and cached in a sidecar file
997
+ of kind `2`. It is therefore limited to what the cells show: it cannot
998
+ be an administrative centre or a label position from the source data.
999
+ A future version could let the encoder supply one.
1000
+ 3. **No exact-fallback marker.** The prototype's approach C reserves a
1001
+ sentinel for cells that should be resolved by exact polygon
1002
+ arithmetic. This format only supports build-time attribution
1003
+ (approach D). A reserved palette index could be added later.
1004
+ 4. **Fixed three-level hierarchy.** Countries whose cities sit directly
1005
+ under the country need a placeholder region.
1006
+ 5. **Global versus per-chunk depth.** `D` is global. A per-chunk depth
1007
+ would let sparse areas stop at coarser cells; whether that is worth
1008
+ the complexity has not been measured.
1009
+ 6. **Name escaping.** `|` cannot appear in a name. No real place name
1010
+ affected by this is known, but there is no escape mechanism.
1011
+
1012
+ ## Appendix A. Worked Example
1013
+
1014
+ This appendix gives a complete, valid, synthetic version `1` file of
1015
+ 157 bytes and walks through several lookups; Section A.6 gives its chunk
1016
+ as version `2` stores it. Its geography is fictional. The file uses
1017
+ a `2 × 2` chunk grid, a quadtree depth of `2`, and name blocks of `4`
1018
+ entries.
1019
+
1020
+ ### A.1. Header (17 bytes)
1021
+
1022
+ ```
1023
+ 43 47 45 4f 44 41 54 41 signature "CGEODATA"
1024
+ 01 version 1
1025
+ 03 4f 53 4d attribution_length 3, attribution "OSM"
1026
+ 01 width_exp 1 -> W = 2
1027
+ 01 height_exp 1 -> H = 2
1028
+ 02 max_depth 2 -> D = 2, codes are 4 bits
1029
+ 02 keyframe_exp 2 -> I = 4 names per block
1030
+ ```
1031
+
1032
+ ### A.2. Directory (5 bytes)
1033
+
1034
+ ```
1035
+ 6d place_table_length 109
1036
+ 00 00 00 1a chunk_lengths: chunk 0, 1, 2 empty; chunk 3 is 26 bytes
1037
+ ```
1038
+
1039
+ Chunk `3` is row `1`, column `1`: latitudes `[0, 90)`, longitudes
1040
+ `[0, 180)`. Its block starts at offset `17 + 5 + 109 = 131` and ends at
1041
+ `157`, the end of the file.
1042
+
1043
+ ### A.3. Place Table (109 bytes)
1044
+
1045
+ Uncompressed prefix (6 bytes):
1046
+
1047
+ ```
1048
+ 02 country_count C = 2
1049
+ 01 01 region_counts: country 0 has 1 region, country 1 has 1 -> R = 2
1050
+ 02 01 city_counts: region 0 has 2 cities, region 1 has 1 -> 3 cities, N = 7
1051
+ 43 block_lengths: block 0 is 67 bytes (K = ceil(7/4) = 2, so K-1 = 1 entry)
1052
+ ```
1053
+
1054
+ The identifier space is:
1055
+
1056
+ | ID | Kind | Parent | Name entry |
1057
+ |----|---------|--------|----------------------------|
1058
+ | 0 | country | | `Nederland\|The Netherlands` |
1059
+ | 1 | country | | `België\|Belgium` |
1060
+ | 2 | region | 0 | `Noord-Holland` |
1061
+ | 3 | region | 1 | `Antwerpen\|Antwerp` |
1062
+ | 4 | city | 2 | `Amsterdam` |
1063
+ | 5 | city | 2 | `Zaandam` |
1064
+ | 6 | city | 3 | `Antwerpen\|Antwerp` |
1065
+
1066
+ Block `0` (IDs 0–3) inflates to
1067
+ `Nederland|The Netherlands\0België|Belgium\0Noord-Holland\0Antwerpen|Antwerp\0`
1068
+ and is stored as these 67 bytes:
1069
+
1070
+ ```
1071
+ 78 da f3 4b 4d 49 2d ca 49 cc 4b a9 09 c9 48 55 f0 4b 2d c9 80 70 8b 19
1072
+ 9c 52 73 d2 33 0f af ae 01 d3 a5 b9 0c 7e f9 f9 45 29 ba 1e f9 39 20 69
1073
+ 06 c7 bc 92 f2 d4 a2 82 d4 bc 1a 28 8b 01 00 2e 70 1c 57
1074
+ ```
1075
+
1076
+ Block `1` (IDs 4–6) inflates to `Amsterdam\0Zaandam\0Antwerpen|Antwerp\0`
1077
+ and is stored as the remaining `109 - 6 - 67 = 36` bytes:
1078
+
1079
+ ```
1080
+ 78 da 73 cc 2d 2e 49 2d 4a 49 cc 65 88 4a 4c cc 03 d1 8e 79 25 e5 a9 45
1081
+ 05 a9 79 35 50 16 03 00 f7 a7 0d 6c
1082
+ ```
1083
+
1084
+ To find the name of ID `5`, a reader inflates block `floor(5 / 4) = 1`
1085
+ and skips `5 mod 4 = 1` entry, arriving at `Zaandam`.
1086
+
1087
+ ### A.4. Chunk 3 (26 bytes compressed)
1088
+
1089
+ Stored bytes:
1090
+
1091
+ ```
1092
+ 78 da 63 62 62 66 67 64 62 62 62 62 64 62 64 62 60 60 60 64 02 00 01 8b
1093
+ 00 21
1094
+ ```
1095
+
1096
+ Inflated content (18 bytes):
1097
+
1098
+ ```
1099
+ 02 palette_count P = 2 -> S = 1
1100
+ 02 03 palette deltas 2, 3 -> IDs 2 (Noord-Holland), 5 (Zaandam)
1101
+ 07 record_count M = 7
1102
+ 01 02 02 02 02 01 02 depths
1103
+ 01 02 00 00 00 01 02 palette_indices -> ID 2, ID 5, none, none, none, ID 2, ID 5
1104
+ ```
1105
+
1106
+ Each record starts where the one before it ends
1107
+ ([Section 8.4](#84-records)). A depth-1 record spans `4^(2-1) = 4`
1108
+ codes and a depth-2 record `1`, so the codes are:
1109
+
1110
+ | Record | Depth | Code | Palette index |
1111
+ |--------|-------|-------------------|---------------|
1112
+ | 0 | 1 | `0` | `1`, ID 2 |
1113
+ | 1 | 2 | `0 + 4 = 4` | `2`, ID 5 |
1114
+ | 2 | 2 | `4 + 1 = 5` | `0`, none |
1115
+ | 3 | 2 | `5 + 1 = 6` | `0`, none |
1116
+ | 4 | 2 | `6 + 1 = 7` | `0`, none |
1117
+ | 5 | 1 | `7 + 1 = 8` | `1`, ID 2 |
1118
+ | 6 | 2 | `8 + 4 = 12` | `2`, ID 5 |
1119
+
1120
+ The last record ends at `12 + 1 = 13`. The seven records cover the
1121
+ chunk's `4 × 4` cell grid as follows (north is up; `A` = Noord-Holland,
1122
+ `B` = Zaandam, `-` = index 0, `.` = no record):
1123
+
1124
+ ```
1125
+ y=3 | A A . .
1126
+ y=2 | A A B .
1127
+ y=1 | A A - -
1128
+ y=0 | A A B -
1129
+ +-----------------
1130
+ x=0 x=1 x=2 x=3
1131
+ ```
1132
+
1133
+ Record `0` is `(code 0, depth 1)`, the depth-1 cell covering codes
1134
+ `0..3`. Record `5` is `(code 8, depth 1)`, covering codes `8..11`. The
1135
+ other five are full-precision cells. Codes `5` to `7` are empty and
1136
+ covered by index-`0` records; codes `13` to `15`, after the last record,
1137
+ have no record. Records `3` and `4` could not be one depth-1 record:
1138
+ codes `6` and `7` are half of the depth-1 cell `4..7`, whose other half
1139
+ holds Zaandam and record `2`.
1140
+
1141
+ ### A.5. Lookups
1142
+
1143
+ `NX = NY = 2 × 2^2 = 8`.
1144
+
1145
+ **`(lat 20, lon 100)`.** `gx = floor(280/360 × 8) = 6`,
1146
+ `gy = floor(110/180 × 8) = 4`. Chunk `c = 1, r = 1`, index `3`; local
1147
+ cell `x = 2, y = 0`, code `q = 4`. The largest stored code `<= 4` is
1148
+ record `1` (`code 4, depth 2`). `shift = 0`, and `4 == 4`, so the point
1149
+ is inside. Palette index `2` selects ID `5`: **Zaandam**, in
1150
+ Noord-Holland, Nederland.
1151
+
1152
+ **`(lat 40, lon 30)`.** `gx = floor(210/360 × 8) = 4`,
1153
+ `gy = floor(130/180 × 8) = 5`. Chunk `3`; local cell `x = 0, y = 1`,
1154
+ `q = 2`. The largest stored code `<= 2` is record `0` (`code 0,
1155
+ depth 1`). `shift = 2 × (2 - 1) = 2`, and `2 >> 2 == 0 >> 2`, so the
1156
+ point is inside that depth-1 cell. Palette index `1` selects ID `2`:
1157
+ **Noord-Holland** (a region-level result).
1158
+
1159
+ **`(lat 30, lon 100)`.** `gx = 6`, `gy = floor(120/180 × 8) = 5`;
1160
+ chunk `3`, local `x = 2, y = 1`, `q = 6`. The largest code `<= 6` is
1161
+ record `3` (`code 6, depth 2`), which matches exactly, but its palette
1162
+ index is `0`: **unknown**.
1163
+
1164
+ **`(lat 20, lon 170)`.** `gx = 7`, `gy = 4`; local `x = 3, y = 0`,
1165
+ `q = 5`. Record `2` matches exactly, and its palette index is `0` too:
1166
+ **unknown**.
1167
+
1168
+ **`(lat 60, lon 170)`.** `gx = 7`, `gy = floor(150/180 × 8) = 6`;
1169
+ chunk `3`, local `x = 3, y = 2`, `q = 13`. The largest code `<= 13` is
1170
+ record `6` (`code 12, depth 2`). `shift = 0` and `13 != 12`, so the
1171
+ point lies after the last record: **unknown**.
1172
+
1173
+ **`(lat -10, lon 10)`.** `gx = 4`, `gy = floor(80/180 × 8) = 3`; chunk
1174
+ `c = 1, r = 0`, index `1`. Its length is `0`: **unknown**, with no
1175
+ decompression performed.
1176
+
1177
+ ### A.6. Chunk 3 as Version 2 (11 bytes)
1178
+
1179
+ As a version `2` file, the example is 142 bytes: the header's `version`
1180
+ byte is `02`, the directory's last chunk length `0b`, and chunk `3` is
1181
+ stored as follows ([Section 8.7](#87-version-2-chunks)):
1182
+
1183
+ ```
1184
+ 02 palette_count P = 2
1185
+ 02 03 palette deltas 2, 3 -> IDs 2, 5
1186
+ 07 record_count M = 7
1187
+ 00 a5 11 64 ba 00 00 stream
1188
+ ```
1189
+
1190
+ The stream holds these decisions, in order. `W` and `S` are the west
1191
+ and south neighbours' records, `L` the move-to-front list before the
1192
+ leaf; every probability used is still at `2048` unless it was used
1193
+ before.
1194
+
1195
+ | Node `(d; x, y)` | Neighbours | Decisions | Record |
1196
+ |------------------|-----------------------------|----------------------------------------------------|--------|
1197
+ | `(0; 0, 0)` | none | `split[0] = 1` | |
1198
+ | `(1; 0, 0)` | none | `split[16] = 0`; `L = 0 1 2`, `r = 1`: `rank_length[0] = 1`, `rank_length[1] = 0`, `rank_bits[32] = 0` | 0: depth 1, index 1 |
1199
+ | `(1; 2, 0)` | W record 0 | `split[20] = 1` | |
1200
+ | `(2; 2, 0)` | W record 0 | `same_west[73] = 0`; `L = 1 0 2`, skipping `1`, `r = 1`: `rank_length[32] = 1`, `rank_length[33] = 0`, `rank_bits[32] = 0` | 1: depth 2, index 2 |
1201
+ | `(2; 3, 0)` | W record 1 | `same_west[73] = 0`; `L = 2 1 0`, skipping `2`, `r = 1`: `rank_length[32] = 1`, `rank_length[33] = 0`, `rank_bits[32] = 0` | 2: depth 2, index 0 |
1202
+ | `(2; 2, 1)` | W record 0, S record 1 | `same_west[65] = 0`, `same_south[65] = 0`; `L = 0 2 1`, skipping `1` and `2`, `r = 0`: `rank_length[96] = 0` | 3: depth 2, index 0 |
1203
+ | `(2; 3, 1)` | W record 3, S record 2 | `same_west[93] = 1` | 4: depth 2, index 0 |
1204
+ | `(1; 0, 2)` | S record 0 | `split[17] = 0`; `same_south[32] = 1` | 5: depth 1, index 1 |
1205
+ | `(1; 2, 2)` | W record 5, S record 3 | `split[22] = 1` | |
1206
+ | `(2; 2, 2)` | W record 5, S record 3 | `same_west[73] = 0`, `same_south[73] = 0`; `L = 1 0 2`, skipping `1` and `0`, `r = 0`: `rank_length[96] = 0` | 6: depth 2, index 2 |
1207
+
1208
+ For example, at `(2; 3, 1)` both neighbours have index `0`, as had the
1209
+ previous record, so `c = 4 × (8 × 2 + 4 + 2 + 1) + 1 = 93`, and since
1210
+ `s = w` no `same_south` decision follows. At `(1; 2, 2)` the south
1211
+ neighbour, record 3, is one level deeper than the node (category `2`),
1212
+ so `split[16 × 1 + 4 × 1 + 2] = split[22]`. Decoding stops after the
1213
+ seventh record, with three nodes of the traversal still unvisited, and
1214
+ `pos` is then `7`, the length of the stream. The records are those of
1215
+ Section A.4.
1216
+
1217
+ ## Appendix B. Text Search Index
1218
+
1219
+ This appendix specifies an OPTIONAL sidecar file that speeds up substring
1220
+ search over place names. It is a separate file, derived entirely from the
1221
+ place table ([Section 7](#7-place-table)) of one CGEODATA file, and it
1222
+ carries file kind `1` ([Section 5](#5-header)).
1223
+
1224
+ ### B.1. Purpose and Properties
1225
+
1226
+ A text search without an index reads every name in the place table and
1227
+ compares it with the query: a linear scan over every name block, which
1228
+ at worldwide scale means inflating the names of over 300,000 places. The
1229
+ index described here lets a reader avoid most of that, in two ways:
1230
+
1231
+ - **Trigram lists** ([Section B.3](#b3-trigrams-and-lists)) record, for
1232
+ every run of three symbols, which places contain it in one of their
1233
+ names. A query of three or more symbols reads only the lists of its own
1234
+ trigrams, and only the places present in all of them can match.
1235
+ - **A short-query table** ([Section B.6](#b6-short-query-table)) answers
1236
+ queries of one or two characters, which have no trigram and match a
1237
+ large part of the table, by storing the first places of their
1238
+ relevance-ordered result directly.
1239
+
1240
+ The index has the following properties:
1241
+
1242
+ - **It covers every place.** Countries, regions, and cities are all
1243
+ indexed, so a query never has to scan any part of the place table
1244
+ linearly while the index applies.
1245
+ - **The trigram lists only over-approximate.** Every step that maps
1246
+ names to lists is many-to-one, so the places they leave over are a
1247
+ superset of the true matches ([Section B.9](#b9-query-procedure)). A
1248
+ reader confirms every candidate by comparing its names, exactly as it
1249
+ would without the index, and MUST produce the same results with and
1250
+ without it.
1251
+ - **It is a pure function of its source.** Two writers given the
1252
+ same source, the same parameters, and the same relevance rule
1253
+ ([Section B.7](#b7-file-layout)) MUST produce byte-identical files.
1254
+ The file carries no timestamp and nothing else that depends on
1255
+ the writer, and nothing in it is compressed, since deflate output is
1256
+ not guaranteed to be identical between zlib implementations. It is
1257
+ bound to its source by a checksum ([Section B.8](#b8-source-checksum)):
1258
+ over the source's place table, or for a short-query table in area
1259
+ order, over everything up to the first chunk.
1260
+ - **It is read in parts.** The header records the length of every
1261
+ section, so a reader reads only the header up front, and afterwards
1262
+ only what a query needs: the list directory and a few lists for a long
1263
+ query, or the table directory and one table block for a short one.
1264
+ - **It is disposable.** Because it is derived, it can be rebuilt from
1265
+ its source at any time.
1266
+
1267
+ ### B.2. Symbol Folding
1268
+
1269
+ Names and queries are reduced in two stages, both used elsewhere in this
1270
+ appendix: first to their **folded form**, a plain string that is
1271
+ diacritic- and case-insensitive; then, for trigram purposes only, further
1272
+ to a sequence of **symbols**, non-negative integers that also collapse
1273
+ every ASCII digit together and every other ASCII punctuation/space
1274
+ character together. The folded form is what [Section B.5](#b5-relevance-order)
1275
+ and [Section B.6](#b6-short-query-table) compare and rank with; the
1276
+ symbol sequence is what trigrams ([Section B.3](#b3-trigrams-and-lists))
1277
+ are taken from. Keeping them distinct matters: the symbol sequence's
1278
+ digit/punctuation bucketing is the right call for keeping the number of
1279
+ trigram lists bounded, but it would make `5th` match `9th` as a
1280
+ substring, which is too loose for deciding whether, or how well, text
1281
+ actually matches a query.
1282
+
1283
+ The folded form is produced by:
1284
+
1285
+ 1. Decompose the text into Unicode Normalization Form D [UAX15].
1286
+ 2. Remove every code point in the Combining Diacritical Marks block,
1287
+ `U+0300` to `U+036F` inclusive.
1288
+ 3. Convert the result to lowercase with the Unicode default case
1289
+ conversion (the locale-independent `toLowercase()` of [UNICODE]
1290
+ Section 3.13).
1291
+
1292
+ Step 1 followed by step 2 turns `é` into `e`. Step 3 turns `E` into `e`.
1293
+ `ß`, `ø`, and `ł`, which have no decomposition, and every letter of a
1294
+ non-Latin script, pass through unchanged apart from case.
1295
+
1296
+ The symbol sequence continues from the folded form with a fourth step,
1297
+ mapping each remaining code point `c` to one symbol:
1298
+
1299
+ | Code points | Symbol |
1300
+ |---------------------------------|--------|
1301
+ | `a` to `z` (`U+0061`–`U+007A`) | `0` to `25` in alphabetical order |
1302
+ | `0` to `9` (`U+0030`–`U+0039`) | `27`, the digit symbol |
1303
+ | any other code point below `U+0080` | `26`, the separator symbol |
1304
+ | any code point from `U+0080` up | `c` itself |
1305
+
1306
+ Step 4 puts all ASCII digits in one bucket and all ASCII spaces and
1307
+ punctuation in another, and keeps every other character distinct: `ß`,
1308
+ `ø`, and `ł` and every letter of a non-Latin script are symbols of their
1309
+ own, same as in the folded form. Symbols `0` to `27` are the **Latin
1310
+ symbols**; every other symbol is at least `128`.
1311
+
1312
+ Both reductions are lossy, but one code point never becomes more than one
1313
+ folded character, and one folded character never becomes more than one
1314
+ symbol, so any text that contains another as a substring contains it as a
1315
+ substring after folding, and after taking symbols, too
1316
+ ([Section B.9](#b9-query-procedure)). Step 4's bucketing means the symbol
1317
+ sequence is a *further*, coarser folding of the folded form -- so a
1318
+ comparison against the folded form alone (Sections B.5, B.6) is stricter
1319
+ than, and therefore safe to confirm trigram-index candidates with, a
1320
+ comparison against the symbol sequence ([Section B.9](#b9-query-procedure)
1321
+ explains why that direction is the one that matters). Neither stage uses
1322
+ any Unicode character property beyond normalization and case conversion,
1323
+ so that a writer and a reader built against different versions of the
1324
+ Unicode Character Database fold the same text the same way. Writers and
1325
+ readers MUST use exactly this procedure for both the folded form and the
1326
+ symbol sequence.
1327
+
1328
+ ### B.3. Trigrams and Lists
1329
+
1330
+ A **trigram** is a run of three consecutive symbols. The trigram set of
1331
+ a place is the union, over every field of its name entry
1332
+ ([Section 7.4](#74-name-entries)), of the trigrams of that field's
1333
+ symbol sequence. Each field is folded separately; no trigram spans the
1334
+ `|` between two fields. A field shorter than three symbols contributes
1335
+ nothing.
1336
+
1337
+ The index has one list per possible **list index**. There are
1338
+
1339
+ ```
1340
+ L = 28^3 + 2^hash_exp = 21952 + 2^hash_exp
1341
+ ```
1342
+
1343
+ list indices. A trigram `(s0, s1, s2)` whose symbols are all Latin has
1344
+ the list index
1345
+
1346
+ ```
1347
+ l = s0 × 784 + s1 × 28 + s2 (0 <= l < 21952)
1348
+ ```
1349
+
1350
+ so every Latin trigram has a list of its own. Any other trigram is
1351
+ hashed into one of `2^hash_exp` shared lists: let `bytes` be the nine
1352
+ bytes formed by writing `s0`, `s1`, and `s2` each as a `u24`
1353
+ ([Section 3.1](#31-fixed-width-integers)), let `h` be the 32-bit
1354
+ FNV-1a hash [FNV] of `bytes`, and fold `h` to `hash_exp` bits:
1355
+
1356
+ ```
1357
+ h = 0x811c9dc5
1358
+ for each byte b of bytes, in order:
1359
+ h = h xor b
1360
+ h = (h × 0x01000193) mod 2^32
1361
+ l = 21952 + (((h >> hash_exp) xor h) mod 2^hash_exp)
1362
+ ```
1363
+
1364
+ Symbols are code points or smaller, so each fits in a `u24`. Test
1365
+ vectors for the 32-bit hash: the empty input hashes to `811c9dc5`, the
1366
+ single byte `a` to `e40c292c`, and the ASCII text `foobar` to
1367
+ `bf9cf968`. Some trigram list indices with `hash_exp = 15`:
1368
+
1369
+ | Text | Trigram | `bytes` | `h` | `l` |
1370
+ |----------|----------------------------|------------------------------|------------|---------|
1371
+ | `łód` | `(0x142, 14, 3)` | `42 01 00 0e 00 00 03 00 00` | `0702848f` | `24650` |
1372
+ | `東京都` | `(0x6771, 0x4eac, 0x90fd)` | `71 67 00 ac 4e 00 fd 90 00` | `574bcbf2` | `47909` |
1373
+ | `straße` | `(0, 0xdf, 4)`, from `aße` | `00 00 00 df 00 00 04 00 00` | `e5f8c954` | `22629` |
1374
+
1375
+ List `l` holds every place whose trigram set contains a trigram with
1376
+ list index `l`. Two hashed trigrams may share a list; that only admits
1377
+ more candidates, never fewer.
1378
+
1379
+ ### B.4. List Encoding
1380
+
1381
+ Each list is a strictly increasing set of place IDs, stored in one of
1382
+ two encodings:
1383
+
1384
+ - **ID list** (encoding `0`): the IDs as a delta-coded list
1385
+ ([Section 3.3](#33-delta-coded-lists)), with no count. The list ends
1386
+ where its stored length ends.
1387
+ - **Bitmap** (encoding `1`): `ceil(N / 8)` bytes, one bit per place of
1388
+ the source, where `N` is the number of places. The bit of place `id`
1389
+ is in byte `id >> 3`, at bit position `id & 7`, least significant bit
1390
+ first. Bits for positions `N` and beyond in the last byte MUST be `0`.
1391
+
1392
+ Writers MUST use the ID list when its encoded length is at most
1393
+ `ceil(N / 8)`, and the bitmap otherwise. The choice is then fixed by the
1394
+ set, which keeps the file a pure function of its source. A list that
1395
+ would be empty is not stored at all ([Section B.7](#b7-file-layout)).
1396
+
1397
+ ### B.5. Relevance Order
1398
+
1399
+ A reader that returns search results ordered by relevance, rather than
1400
+ by ID, SHOULD use this order or the area order of
1401
+ [Section B.5.1](#b51-area-order), and the short-query table
1402
+ ([Section B.6](#b6-short-query-table)) MUST be built with the one its
1403
+ `relevance_rule` names ([Section B.7](#b7-file-layout)).
1404
+
1405
+ A place **matches** a query when the folded form
1406
+ ([Section B.2](#b2-symbol-folding)) of at least one field of its name
1407
+ entry contains the folded form of the query as a substring. Folding
1408
+ before comparing means a query need not be typed with the right
1409
+ diacritics: `zurich` matches a field spelled `Zürich`.
1410
+
1411
+ The **tier** of a field that contains the query, against the folded
1412
+ form of both, is:
1413
+
1414
+ - `40` when the field's folded form equals the query's;
1415
+ - otherwise `20` when the query's **tokens** occur in the field's tokens
1416
+ as a contiguous run, where the tokens of a text are its folded form
1417
+ split at every code point whose General Category is not a letter (`L*`)
1418
+ or a number (`N*`), with empty tokens dropped;
1419
+ - otherwise `10`.
1420
+
1421
+ A field that does not contain the query folded has tier `0` and, with
1422
+ it, **quality** `0`: nothing below distinguishes a non-match. A field
1423
+ that does contain it gets `1` added to its folded tier -- an **exact
1424
+ spelling bonus** -- when the *unfolded* comparison (plain lowercase, no
1425
+ decomposition or diacritic stripping) reaches that same tier against the
1426
+ *unfolded* query, i.e. when folding was not actually needed to reach it.
1427
+ The unfolded comparison can never reach a *better* tier than the folded
1428
+ one -- folding only ever adds matches -- so "reaches at least the same
1429
+ tier" is exactly "the query's own spelling, as given, was already
1430
+ enough". Unlike the folded tier itself, and unlike
1431
+ [Section B.9](#b9-query-procedure)'s confirmation step, which compares
1432
+ folded forms, the bonus is evaluated with no normalization beyond
1433
+ lowercasing: it decides only how well a field matches, never whether it
1434
+ matches at all, so it can be stricter than the comparison the index's
1435
+ guarantee rests on without ever losing a match. A field's **quality** is
1436
+ its folded tier plus this bonus, so quality is one of `0`, `10`, `11`,
1437
+ `20`, `21`, `40`, `41`.
1438
+
1439
+ The quality of a place is the highest quality of its fields, and its
1440
+ **score** is its quality plus a level bonus: `3` for a country, `2` for
1441
+ a city, `1` for a region. Results are ordered by descending score,
1442
+ places with equal scores by descending context quality
1443
+ ([Section B.13](#b13-qualified-queries)), which is `0` for a query
1444
+ without contexts, and then by ascending ID.
1445
+
1446
+ The level bonus only ever breaks a tie between two places of equal
1447
+ quality: its spread (`3 - 1 = 2`) is kept well under the gap between any
1448
+ two quality values that differ in folded tier (`11` to `20` is `9`, `21`
1449
+ to `40` is `19`), so a worse tier can never outscore a better one no
1450
+ matter which levels are involved, and the exact spelling bonus can never
1451
+ promote a field past the next tier either. A country outranks a
1452
+ same-quality city or region specifically because a query that exactly
1453
+ names a country is a rarer, more deliberate kind of search than one
1454
+ that merely happens to match one of the many more numerous cities or
1455
+ regions sharing the text -- a plain reversal of city and region was
1456
+ deliberately not used instead, since it would equally rank, say, a
1457
+ *province* named Antwerpen above the *city* of Antwerp on an identical
1458
+ exact match, which is backwards for the far more common case of
1459
+ searching a city's own name; a city therefore still outranks a region of
1460
+ equal quality, exactly as if countries did not exist in the formula.
1461
+
1462
+ For example, the query `amsterdam` gives the city `Amsterdam` quality
1463
+ `41` (folded tier `40`, an exact match that needed no folding) and score
1464
+ `43`, and the city `Nieuw-Amsterdam` quality `21` (folded tier `20`; its
1465
+ tokens are `nieuw`, `amsterdam`) and score `23`. The query `belgie`
1466
+ (typed without the diaeresis) gives the country `België` folded tier
1467
+ `40` (an exact match once both are folded to `belgie`) but quality `40`,
1468
+ not `41`: the unfolded comparison, `belgië` against `belgie`, does not
1469
+ reach an exact match (or even a substring match) on its own, so the
1470
+ spelling bonus does not apply; querying `belgië` instead reaches quality
1471
+ `41`. The query ` amsterdam` with a leading space matches neither: token
1472
+ matching only ranks places that already match.
1473
+
1474
+ Only the ranking depends on Unicode character properties, never whether
1475
+ a place matches, so a reader and writer that disagree about a character's
1476
+ category can disagree about order but not about the set of results.
1477
+
1478
+ #### B.5.1. Area Order
1479
+
1480
+ Among places of equal score, the order above falls back to IDs, which
1481
+ carry no meaning: the query `berlin` would list a dozen towns in the
1482
+ United States before the city-state of Berlin. A reader that knows the
1483
+ area of every place -- the area bytes of
1484
+ [Section C.3](#c3-representative-cell), which a place location index
1485
+ stores -- MAY instead order results by area, so that among equally good
1486
+ matches a large place comes first. Whether to is the application's
1487
+ choice, and a reader SHOULD let it make it. A reader MUST NOT use this
1488
+ order without the areas, since a reader that has them and one that does
1489
+ not would then disagree.
1490
+
1491
+ The **rank area** of a country or a city is its area byte. The rank
1492
+ area of a region is also its area byte, unless one or more of its cities
1493
+ has a local name (field `0`, [Section 7.4](#74-name-entries)) whose
1494
+ folded form ([Section B.2](#b2-symbol-folding)) equals that of the
1495
+ region's own local name: then it is the largest area byte among those
1496
+ cities. A province would otherwise come before its own capital of the
1497
+ same name (the province of Utrecht before the city of Utrecht) for no
1498
+ reason but its size, which Section B.5's level bonus exists to prevent;
1499
+ with this rule it comes right after it, while a city-state with no city
1500
+ of its own name (Berlin, Vienna) still ranks by its own area.
1501
+
1502
+ In area order, places are compared on the following keys in turn, each
1503
+ one only deciding between places equal on all keys before it:
1504
+
1505
+ 1. the folded tier of their quality ([Section B.5](#b5-relevance-order),
1506
+ quality without the exact spelling bonus), higher first;
1507
+ 2. their context quality ([Section B.13](#b13-qualified-queries)),
1508
+ higher first;
1509
+ 3. countries before regions and cities;
1510
+ 4. their rank area, higher first;
1511
+ 5. the exact spelling bonus, present first;
1512
+ 6. cities before regions;
1513
+ 7. their ID, lower first.
1514
+
1515
+ The exact spelling bonus comes after the area, unlike in Section B.5's
1516
+ score, or the query `zurich` would rank a village spelled `Zurich` ahead
1517
+ of `Zürich` whatever their sizes. Countries keep their precedence for
1518
+ the reason Section B.5 gives.
1519
+
1520
+ For example, the query `dam` against the file of
1521
+ [Appendix A](#appendix-a-worked-example) matches `Amsterdam` and
1522
+ `Zaandam`, both with quality `11` and score `13`. Section B.5 orders them
1523
+ by ID, `Amsterdam` first. In area order `Zaandam`, with area byte `5`
1524
+ ([Section C.8](#c8-worked-example)), comes first, and `Amsterdam`, which
1525
+ has no cells and so area byte `0`, second.
1526
+
1527
+ Area order matches the same places as Section B.5 and only orders them
1528
+ differently.
1529
+
1530
+ ### B.6. Short-Query Table
1531
+
1532
+ A query of one or two characters has no trigram, and matches so many
1533
+ places that comparing every name is the only way to rank them. The
1534
+ short-query table instead stores, for every such query that has any
1535
+ match, the first `top_count` places in relevance order
1536
+ ([Section B.5](#b5-relevance-order)).
1537
+
1538
+ The table's **keys** are every string of one or two consecutive code
1539
+ points that occurs in the folded form ([Section B.2](#b2-symbol-folding))
1540
+ of some field of some name entry. The table MUST contain every key and
1541
+ no other. The **entry** of a key is the list of the places that match
1542
+ it, in the relevance order the file's `relevance_rule` names
1543
+ ([Section B.5](#b5-relevance-order) or
1544
+ [Section B.5.1](#b51-area-order), scoring the key itself as the query),
1545
+ truncated to its first `top_count` places. A
1546
+ key always has at least one match, so an entry is never empty; it has
1547
+ fewer than `top_count` places only when fewer places match. A query
1548
+ whose folded form is one or two code points long and is not a key
1549
+ matches no place at all.
1550
+
1551
+ Because a key is already in folded form, scoring it as a query can never
1552
+ need Section B.5's exact spelling bonus to be anything other than
1553
+ whatever the key's own, already-folded spelling gives it -- a key never
1554
+ carries a diacritic of its own to fold away. A *query* that does,
1555
+ though, may need a different bonus than its key would: `e` and `é` both
1556
+ fold to the key `e`, but a field spelled with an actual `é` reaches the
1557
+ exact spelling bonus against the query `é` and not against the query
1558
+ `e`, which the table cannot represent with one entry per key. A reader
1559
+ therefore MUST NOT answer a query from this table unless the query's own
1560
+ folded form already equals its unfolded (plain lowercase) form, i.e. the
1561
+ query itself has no diacritic to fold -- see [Section B.9](#b9-query-procedure)'s
1562
+ step 1.
1563
+
1564
+ Entries are sorted by the UTF-8 bytes of their key, compared bytewise
1565
+ (which equals comparing code points), and grouped into **table blocks**
1566
+ of `2^top_block_exp` consecutive entries; the last block MAY be shorter.
1567
+ A table block is the concatenation of its entries, each stored as:
1568
+
1569
+ | Field | Type | Description |
1570
+ |---------|---------------|-------------|
1571
+ | `key` | bytes, `NUL` | The key in UTF-8, followed by a `NUL` byte. |
1572
+ | `count` | varint | The number of places in the entry, from `1` to `top_count`. |
1573
+ | `ids` | `count` varints | The places, in relevance order. Not delta-coded: relevance order is not ID order. |
1574
+
1575
+ The **table directory** lists, for each block, the key of its first
1576
+ entry, so that a reader finds the block of a key by binary search over
1577
+ the directory and then reads that block alone:
1578
+
1579
+ | Field | Type | Description |
1580
+ |-----------------|---------------|-------------|
1581
+ | `key_count` | varint | `Q`, the number of keys. There are `ceil(Q / 2^top_block_exp)` blocks. |
1582
+ | for each block: `first_key` | bytes, `NUL` | The key of the block's first entry, in UTF-8, followed by `NUL`. |
1583
+ | for each block: `block_length` | varint | The byte length of the block. |
1584
+
1585
+ Blocks are stored consecutively in block order, so block `b` starts at
1586
+ the sum of the lengths of blocks `0` to `b - 1`.
1587
+
1588
+ ### B.7. File Layout
1589
+
1590
+ The file is a header followed by four sections, with no padding and no
1591
+ trailer.
1592
+
1593
+ | Field | Type | Description |
1594
+ |-------------------------|---------|-------------|
1595
+ | `signature` | 8 bytes | The ASCII bytes `CGEODATA`, as in [Section 5](#5-header). |
1596
+ | `version` | varint | Kind and version as defined in Section 5. This appendix specifies kind `1`, version `3`, so the value is `19` (`13`). Version `2` had no `relevance_rule` field, its short-query table always in Section B.5's order; a reader MUST reject it. Version `1` built the short-query table from the unfolded lowercase form and a different level bonus ordering (city highest, not country); a version-1 file is not just an older layout but a different, incompatible relevance order, and nothing in its bytes records which rule built it, since `source_checksum` covers only the place table, not the relevance rule -- a reader MUST reject it rather than answer queries with it. |
1597
+ | `source_checksum` | u64 | Checksum of the source file's place table ([Section B.8](#b8-source-checksum)). |
1598
+ | `place_count` | varint | `N`, the number of places in the source. |
1599
+ | `hash_exp` | u8 | The number of hashed lists is `2^hash_exp` ([Section B.3](#b3-trigrams-and-lists)). MUST be from `1` to `24`. |
1600
+ | `top_count` | u8 | The number of places per short-query entry ([Section B.6](#b6-short-query-table)). `0` means the file has no short-query table. |
1601
+ | `top_block_exp` | u8 | Each table block holds `2^top_block_exp` entries. MUST be at most `24`. |
1602
+ | `relevance_rule` | u8 | The order of the short-query table ([Section B.6](#b6-short-query-table)): `0` for [Section B.5](#b5-relevance-order)'s, `1` for the area order of [Section B.5.1](#b51-area-order). Other values are reserved. Also decides what `source_checksum` covers ([Section B.8](#b8-source-checksum)). |
1603
+ | `list_directory_length` | varint | Byte length of `list_directory`. |
1604
+ | `lists_length` | varint | Byte length of `lists`. |
1605
+ | `table_directory_length`| varint | Byte length of `table_directory`. |
1606
+ | `list_directory` | bytes | See below. |
1607
+ | `lists` | bytes | The stored lists, in increasing list index, each in its encoding ([Section B.4](#b4-list-encoding)). |
1608
+ | `table_directory` | bytes | The table directory of Section B.6. Empty when `top_count` is `0`. |
1609
+ | `table_blocks` | bytes | The table blocks of Section B.6, in block order. They run to the end of the file. Empty when `top_count` is `0`. |
1610
+
1611
+ The list directory records which lists are stored and how long each
1612
+ one is:
1613
+
1614
+ | Field | Type | Description |
1615
+ |------------|-----------------------|-------------|
1616
+ | `presence` | `ceil(L / 8)` bytes | Bit `l` is `1` if list `l` is stored, that is, if it is not empty. Bit `l` is in byte `l >> 3`, at bit position `l & 7`, least significant bit first. Bits for `L` and beyond in the last byte MUST be `0`. |
1617
+ | `entries` | one varint per stored list | In increasing list index: `length × 2 + encoding`, where `length` is the byte length of the stored list and `encoding` is `0` for an ID list and `1` for a bitmap. |
1618
+
1619
+ List `l`, if stored, starts at the sum of the lengths of the stored
1620
+ lists with a smaller index. A reader computes all offsets with one pass
1621
+ over `entries`. A list that is not stored is empty: no place has a
1622
+ trigram with that list index.
1623
+
1624
+ Version `0` of kind `1` (value `16`) was an earlier bigram layout of
1625
+ this index. Readers MUST reject it.
1626
+
1627
+ ### B.8. Source Checksum
1628
+
1629
+ `source_checksum` binds an index to the place table it was built from.
1630
+ It is the 64-bit FNV-1a hash [FNV] of exactly the `place_table_length`
1631
+ bytes of the source file's place table ([Section 7.2](#72-layout)),
1632
+ starting at the first byte after `chunk_lengths`
1633
+ ([Section 6.2](#62-layout)):
1634
+
1635
+ ```
1636
+ h = 0xcbf29ce484222325
1637
+ for each byte b of the place table, in file order:
1638
+ h = h xor b
1639
+ h = (h × 0x100000001b3) mod 2^64
1640
+ ```
1641
+
1642
+ The result is stored as a `u64`, least significant byte first. Test
1643
+ vectors: the empty input hashes to `cbf29ce484222325`, the single byte
1644
+ `a` to `af63dc4c8601ec8c`, and the ASCII text `foobar` to
1645
+ `85944171f73967e8`.
1646
+
1647
+ Only the place table is covered, not the whole source file, for two
1648
+ reasons. The index depends on nothing else, so a source rebuilt with
1649
+ different chunk parameters, or with some chunks left empty, keeps the
1650
+ same index valid. And verifying the checksum then reads only the place
1651
+ table, which stays small (about 2 MiB for the worldwide file at the
1652
+ recommended `keyframe_exp` of [Section 7.3](#73-name-blocks)), rather
1653
+ than every chunk.
1654
+
1655
+ A short-query table in area order (`relevance_rule = 1`) depends on the
1656
+ areas of [Section C.3](#c3-representative-cell) as well, which depend on
1657
+ the chunks. For such an index, `source_checksum` is instead the checksum
1658
+ of [Section C.4](#c4-file-layout): of the source file from its first
1659
+ byte up to the first chunk, which covers the chunk lengths.
1660
+
1661
+ Readers SHOULD compute the checksum of the source's place table (or
1662
+ prefix) when they load an index, and a reader that does so MUST reject
1663
+ an index whose `source_checksum` differs. A reader MAY skip the check where the
1664
+ build pipeline guarantees the pairing, but it then has no protection
1665
+ against a stale index, which silently misses places whose names were
1666
+ added or changed after the index was built. The checksum detects
1667
+ accidental mismatches; it is not a defence against a deliberately
1668
+ crafted index ([Section B.10](#b10-robustness)).
1669
+
1670
+ FNV-1a was chosen over a cryptographic hash because it is a dozen lines
1671
+ of integer arithmetic in any language and needs no library. In
1672
+ JavaScript, where 64-bit integers are not native, the multiplication is
1673
+ convenient to implement on two 32-bit halves: because the prime is
1674
+ `2^40 + 0x1b3`, `h × prime` is `(h << 40) + h × 0x1b3`, and `h << 40`
1675
+ only ever contributes `low32(h) << 8` to the high half.
1676
+
1677
+ ### B.9. Query Procedure
1678
+
1679
+ To search for a query text:
1680
+
1681
+ 1. **Short queries.** Let `q` be the folded form of the query
1682
+ ([Section B.2](#b2-symbol-folding)). If `q` is one or two code points
1683
+ long, the search asks for results in the relevance order that
1684
+ `relevance_rule` names, with a limit of at most `top_count` and no
1685
+ restriction by level or parent, `top_count` is not `0`, the query
1686
+ has no comma ([Section B.13](#b13-qualified-queries)), and `q`
1687
+ already equals the plain lowercase form of the query (i.e. the query
1688
+ has no diacritic of its own to fold --
1689
+ [Section B.6](#b6-short-query-table) explains why this matters), then
1690
+ look `q` up in the short-query table: find the last block whose
1691
+ `first_key` is at most `q`, read that block, and scan it for `q`. The
1692
+ result is the first `limit` places of its entry, or nothing if `q` is
1693
+ not a key. Stop.
1694
+ 2. **Fold the query** further, with step 4 of
1695
+ [Section B.2](#b2-symbol-folding), into a symbol sequence
1696
+ `s_0 .. s_{m-1}`. If `m < 3`, the query has no trigram and the lists
1697
+ cannot help: compare every name without the index, and stop.
1698
+ 3. **Collect the distinct list indices** of the query's trigrams
1699
+ ([Section B.3](#b3-trigrams-and-lists)). If any of them is not
1700
+ stored, no place can match: the result is empty.
1701
+ 4. **Intersect the lists.** The candidates are the places present in
1702
+ every one of them. A reader SHOULD start from the shortest stored
1703
+ list and MAY stop as soon as the intersection is empty. An ID list
1704
+ is intersected by merging two sorted sequences; a bitmap by testing
1705
+ one bit per remaining candidate.
1706
+ 5. **Confirm each candidate** by comparing its names with the query, as
1707
+ the reader would without the index, and report the confirmed ones.
1708
+ Candidates come out in increasing ID order, which is the order of a
1709
+ search without relevance ranking.
1710
+
1711
+ A qualified query ([Section B.13](#b13-qualified-queries)) takes steps 2
1712
+ to 4 once for the head of each of its readings: the candidates of the
1713
+ query are the union of the candidates of its heads, and if any head has
1714
+ no trigram, every name is compared.
1715
+
1716
+ The lists never lose a match, under the following condition. Say a
1717
+ reader matches a name against a query when the name's symbol sequence
1718
+ contains the query's symbol sequence as a (contiguous) subsequence --
1719
+ the comparison the trigram lists are actually built from. Then a
1720
+ matching name contains every trigram of the query's symbol sequence, so
1721
+ the place is present in every list of step 4 and is examined in step 5.
1722
+ A reader whose comparison is stricter than this inherits the guarantee,
1723
+ since everything it accepts is also accepted by the symbol-sequence
1724
+ comparison. The folded-form substring match of
1725
+ [Section B.5](#b5-relevance-order) is one such stricter comparison: step
1726
+ 4 of Section B.2 maps each folded-form code point to one symbol, so a
1727
+ folded-form substring relationship survives into the symbol sequence
1728
+ unchanged, the same argument Section B.2 makes for why neither folding
1729
+ stage ever loses a match the other would find. A reader whose comparison
1730
+ is looser, for example one that tolerates a missing or transposed
1731
+ character, or that matches across the `|` between fields, does not
1732
+ inherit the guarantee, and MUST NOT use the index for such queries. In
1733
+ particular, a reader that ranks by tokens MUST only rank places that
1734
+ match as a folded substring, as Section B.5 requires; ranking a place
1735
+ whose tokens match but whose names do not contain the query as a folded
1736
+ substring would make results depend on the index. The exotic cases in
1737
+ which lowercasing and decomposition do not commute are not known to
1738
+ affect any place name.
1739
+
1740
+ The short-query table of step 1 is exact rather than an
1741
+ over-approximation: its entries are the answer. A reader SHOULD still
1742
+ confirm that each place of an entry matches `q`, which costs at most
1743
+ `top_count` name lookups, and drop any that do not.
1744
+
1745
+ ### B.10. Robustness
1746
+
1747
+ A search index file may come from an untrusted source, or may be stale.
1748
+ Readers MUST NOT assume that it is well formed or that it matches its
1749
+ source.
1750
+
1751
+ - Readers MUST verify the signature, kind, and version before
1752
+ interpreting any other field, and MUST reject `hash_exp` outside `1`
1753
+ to `24`, `top_block_exp` above `24`, and a `relevance_rule` other than
1754
+ `0` or `1`.
1755
+ - Readers MUST check that the header's section lengths add up to at
1756
+ most the file length, and that `list_directory_length` equals
1757
+ `ceil(L / 8)` plus the length of `entries`, where the number of
1758
+ entries is the number of `1` bits in `presence`.
1759
+ - Readers MUST check that the lengths in `entries` add up to
1760
+ `lists_length`, that every bitmap is exactly `ceil(N / 8)` bytes, and
1761
+ that every block length in the table directory lies within
1762
+ `table_blocks`.
1763
+ - Readers MUST check that `place_count` equals `N`, the number of places
1764
+ in the source, and MUST reject any place ID in a list or table entry
1765
+ that is not less than `N`, and any ID list that is not strictly
1766
+ increasing.
1767
+ - Readers MUST confirm every trigram candidate by comparing its names.
1768
+ Given this, a malformed or mismatched list can cause missed results
1769
+ and wasted work, but never a wrong result. A malformed short-query
1770
+ table can reorder or omit results; confirming its places, as
1771
+ Section B.9 recommends, keeps it from adding a wrong one.
1772
+ - Nothing in the file is compressed, so there is no decompression to
1773
+ bound. The allocations a query needs are bounded by the lengths of the
1774
+ sections and lists it reads, which are bounded by the file length.
1775
+
1776
+ ### B.11. Choosing Parameters
1777
+
1778
+ This section is informative. The measurements were taken on the
1779
+ worldwide file (239 countries, 5,469 regions, 313,732 cities), with a
1780
+ reader that opens the source afresh for every query, as a search box
1781
+ queried only occasionally would: nothing is cached except by the
1782
+ operating system. Each query asks for the top five places in relevance
1783
+ order and resolves them to their parents.
1784
+
1785
+ **Hashed lists.** With `hash_exp = 15` the file holds 32,768 hashed
1786
+ lists beside the 21,952 Latin ones; the presence bitmap is 6.7 KiB, and
1787
+ a query of a script other than Latin leaves about as few candidates as
1788
+ a Latin one of the same length. With the 28-symbol folding of the
1789
+ earlier bigram version, which mapped every non-Latin letter to the
1790
+ separator, a three-letter Cyrillic, Arabic, or Chinese query left every
1791
+ place with a non-Latin name, over 36,000 cities, as candidates.
1792
+ `hash_exp = 15` is RECOMMENDED.
1793
+
1794
+ **Size.** The worldwide index is 4.2 MiB: 3.8 MiB of lists (36,317
1795
+ stored), a 49 KiB list directory, and 362 KiB of short-query table.
1796
+ Every trigram list turned out smaller as an ID list than as a bitmap:
1797
+ an ID list costs about a byte per place, so a bitmap only wins for a
1798
+ trigram shared by more than about one place in eight, which the
1799
+ worldwide data does not have, but a small file (such as the example
1800
+ below) does. The index is built in under three seconds.
1801
+
1802
+ **Speed.** How long a query takes depends far more on the source's
1803
+ `keyframe_exp` ([Section 7.3](#73-name-blocks)) than on the index,
1804
+ because confirming a candidate means inflating the name block it is in.
1805
+ Mean times for random substrings of real city names, with and without
1806
+ the index; every query opens the source and the index afresh, including
1807
+ verifying the checksum (about 10 ms of each indexed query):
1808
+
1809
+ | `keyframe_exp` | Index | 1 character | 2 characters | 3 characters | 5 characters | 8 characters | 95th percentile |
1810
+ |----------------|-------|-------------|--------------|--------------|--------------|--------------|-----------------|
1811
+ | `13` | yes | 15 ms | 13 ms | 67 ms | 24 ms | 15 ms | 88 ms |
1812
+ | `13` | no | 155 ms | 127 ms | 124 ms | 123 ms | 122 ms | 169 ms |
1813
+ | `7` | yes | 11 ms | 10 ms | 26 ms | 13 ms | 12 ms | 34 ms |
1814
+ | `7` | no | 181 ms | 141 ms | 138 ms | 136 ms | 135 ms | 200 ms |
1815
+
1816
+ The one- and two-character rows are answered by the short-query table.
1817
+ Intersecting the lists takes well under a millisecond in every case; the
1818
+ rest of a three-character query is confirming its candidates, of which
1819
+ there are thousands for the commonest trigrams.
1820
+
1821
+ **Short-query table.** With `top_count = 5` the worldwide table has
1822
+ 25,497 keys and takes 365 KiB. It replaces the whole-table
1823
+ scan that one- and two-character queries otherwise need, for the
1824
+ common case of a search box that shows the top few matches.
1825
+ `top_count = 5` and `top_block_exp = 6` (blocks of 64 keys, roughly
1826
+ 1 KiB each) are RECOMMENDED. A reader asked for more results, or for
1827
+ results restricted by level or parent, falls back to the scan for these
1828
+ queries.
1829
+
1830
+ **Why trigrams.** Bigrams (the earlier version of this index) are
1831
+ common enough that a query leaves several times more candidates than
1832
+ with trigrams, and with bigrams pooled into groups of places to keep
1833
+ the file small, more again: for Latin queries of three or more
1834
+ characters with on average 530 true matches among the cities, the
1835
+ earlier layout left 3,500 cities as candidates, where trigrams leave
1836
+ 650. Longer n-grams would narrow queries of four or more characters
1837
+ further, but these are already fast, and would serve no query of
1838
+ three.
1839
+
1840
+ ### B.12. Worked Example
1841
+
1842
+ This example indexes the source file of
1843
+ [Appendix A](#appendix-a-worked-example) with `hash_exp = 4`,
1844
+ `top_count = 2`, and `top_block_exp = 4`: small parameters, so that
1845
+ the example is short but still has several table blocks. Its
1846
+ short-query table is in Section B.5's order (`relevance_rule = 0`). The
1847
+ seven places and their name fields are:
1848
+
1849
+ | ID | Level | Fields |
1850
+ |----|---------|-------------------------------|
1851
+ | 0 | country | `Nederland`, `The Netherlands` |
1852
+ | 1 | country | `België`, `Belgium` |
1853
+ | 2 | region | `Noord-Holland` |
1854
+ | 3 | region | `Antwerpen`, `Antwerp` |
1855
+ | 4 | city | `Amsterdam` |
1856
+ | 5 | city | `Zaandam` |
1857
+ | 6 | city | `Antwerpen`, `Antwerp` |
1858
+
1859
+ `L = 21952 + 2^4 = 21968`, so `presence` is `2746` bytes. `N = 7`, so a
1860
+ bitmap is `1` byte, and any list of two or more places is stored as a
1861
+ bitmap, since its ID list would take two bytes or more. The file is
1862
+ `3202` bytes: a 26-byte header, a `2793`-byte list directory, `47` bytes
1863
+ of lists, a `16`-byte table directory, and `320` bytes of table blocks.
1864
+
1865
+ #### B.12.1. Header (26 bytes)
1866
+
1867
+ ```
1868
+ 43 47 45 4f 44 41 54 41 signature "CGEODATA"
1869
+ 13 version 19 -> kind 1 (text search index), version 3
1870
+ 9f e6 00 b9 37 18 dc 77 source_checksum 0x77dc1837b900e69f
1871
+ 07 place_count 7
1872
+ 04 hash_exp 4 -> 16 hashed lists, L = 21968
1873
+ 02 top_count 2
1874
+ 04 top_block_exp 4 -> 16 entries per table block
1875
+ 00 relevance_rule 0 -> Section B.5's order
1876
+ e9 15 list_directory_length 2793
1877
+ 2f lists_length 47
1878
+ 10 table_directory_length 16
1879
+ ```
1880
+
1881
+ The checksum is the FNV-1a 64 hash of the 109 bytes of the place table
1882
+ in [Section A.3](#a3-place-table-109-bytes), that is the bytes at file
1883
+ offsets `22` to `130` of the Appendix A file, from the `02` of
1884
+ `country_count` to the `6c` that ends block `1`.
1885
+
1886
+ #### B.12.2. Lists
1887
+
1888
+ Every name folds to Latin symbols only (`België` becomes `belgie`), so
1889
+ no hashed list is used. The 47 stored lists, in list index order, are
1890
+ below; `-` stands for the separator symbol `26`. "Bit" is the `presence`
1891
+ byte and bit that mark the list as stored, "Entry" is its varint in
1892
+ `entries`, and "Stored" is the list itself.
1893
+
1894
+ | Trigram | `l` | Bit | Entry | Stored | Places |
1895
+ |---------|-------|--------------|-------|-------------|--------|
1896
+ | `aan` | 13 | 1: `20` | `02` | IDs `05` | 5 |
1897
+ | `ams` | 354 | 44: `04` | `02` | IDs `04` | 4 |
1898
+ | `and` | 367 | 45: `80` | `03` | bitmap `25` | 0, 2, 5 |
1899
+ | `ant` | 383 | 47: `80` | `03` | bitmap `48` | 3, 6 |
1900
+ | `bel` | 907 | 113: `08` | `02` | IDs `01` | 1 |
1901
+ | `dam` | 2364 | 295: `10` | `03` | bitmap `30` | 4, 5 |
1902
+ | `der` | 2481 | 310: `02` | `02` | IDs `00` | 0 |
1903
+ | `d-h` | 3087 | 385: `80` | `02` | IDs `02` | 2 |
1904
+ | `ede` | 3224 | 403: `01` | `02` | IDs `00` | 0 |
1905
+ | `elg` | 3450 | 431: `04` | `02` | IDs `01` | 1 |
1906
+ | `erd` | 3615 | 451: `80` | `02` | IDs `04` | 4 |
1907
+ | `erl` | 3623 | 452: `80` | `02` | IDs `00` | 0 |
1908
+ | `erp` | 3627 | 453: `08` | `03` | bitmap `48` | 3, 6 |
1909
+ | `eth` | 3675 | 459: `08` | `02` | IDs `00` | 0 |
1910
+ | `e-n` | 3877 | 484: `20` | `02` | IDs `00` | 0 |
1911
+ | `gie` | 4932 | 616: `10` | `02` | IDs `01` | 1 |
1912
+ | `giu` | 4948 | 618: `10` | `02` | IDs `01` | 1 |
1913
+ | `her` | 5617 | 702: `02` | `02` | IDs `00` | 0 |
1914
+ | `he-` | 5626 | 703: `04` | `02` | IDs `00` | 0 |
1915
+ | `hol` | 5891 | 736: `08` | `02` | IDs `02` | 2 |
1916
+ | `ium` | 6844 | 855: `10` | `02` | IDs `01` | 1 |
1917
+ | `lan` | 8637 | 1079: `20` | `03` | bitmap `05` | 0, 2 |
1918
+ | `lgi` | 8800 | 1100: `01` | `02` | IDs `01` | 1 |
1919
+ | `lla` | 8932 | 1116: `10` | `02` | IDs `02` | 2 |
1920
+ | `mst` | 9931 | 1241: `08` | `02` | IDs `04` | 4 |
1921
+ | `nda` | 10276 | 1284: `10` | `02` | IDs `05` | 5 |
1922
+ | `nds` | 10294 | 1286: `40` | `02` | IDs `00` | 0 |
1923
+ | `ned` | 10307 | 1288: `08` | `02` | IDs `00` | 0 |
1924
+ | `net` | 10323 | 1290: `08` | `02` | IDs `00` | 0 |
1925
+ | `noo` | 10598 | 1324: `40` | `02` | IDs `02` | 2 |
1926
+ | `ntw` | 10746 | 1343: `04` | `03` | bitmap `48` | 3, 6 |
1927
+ | `oll` | 11295 | 1411: `80` | `02` | IDs `02` | 2 |
1928
+ | `oor` | 11385 | 1423: `02` | `02` | IDs `02` | 2 |
1929
+ | `ord` | 11455 | 1431: `80` | `02` | IDs `02` | 2 |
1930
+ | `pen` | 11885 | 1485: `20` | `03` | bitmap `48` | 3, 6 |
1931
+ | `rda` | 13412 | 1676: `10` | `02` | IDs `04` | 4 |
1932
+ | `rd-` | 13438 | 1679: `40` | `02` | IDs `02` | 2 |
1933
+ | `rla` | 13636 | 1704: `10` | `02` | IDs `00` | 0 |
1934
+ | `rpe` | 13752 | 1719: `01` | `03` | bitmap `48` | 3, 6 |
1935
+ | `ste` | 14648 | 1831: `01` | `02` | IDs `04` | 4 |
1936
+ | `ter` | 15025 | 1878: `02` | `02` | IDs `04` | 4 |
1937
+ | `the` | 15096 | 1887: `01` | `02` | IDs `00` | 0 |
1938
+ | `twe` | 15516 | 1939: `10` | `03` | bitmap `48` | 3, 6 |
1939
+ | `wer` | 17377 | 2172: `02` | `03` | bitmap `48` | 3, 6 |
1940
+ | `zaa` | 19600 | 2450: `01` | `02` | IDs `05` | 5 |
1941
+ | `-ho` | 20594 | 2574: `04` | `02` | IDs `02` | 2 |
1942
+ | `-ne` | 20752 | 2594: `01` | `02` | IDs `00` | 0 |
1943
+
1944
+ All other `presence` bytes are `00`. The entries and the lists are the
1945
+ "Entry" and "Stored" columns concatenated: `entries` is 47 bytes, one
1946
+ varint per list, and `lists` is 47 bytes, since every stored list here
1947
+ is one byte long. The ID list of a single place is its ID, since the
1948
+ first delta is taken from `0`. The place table's `The Netherlands` and
1949
+ `Noord-Holland` contribute the separator trigrams `e-n`, `he-`, `-ne`,
1950
+ `d-h`, `rd-`, and `-ho`.
1951
+
1952
+ #### B.12.3. Short-Query Table
1953
+
1954
+ The names' folded forms contain 63 distinct strings of one or two code
1955
+ points, so the table has four blocks: three of 16 entries and one of
1956
+ 15. The table directory (16 bytes) is:
1957
+
1958
+ ```
1959
+ 3f key_count 63 -> 4 blocks
1960
+ 20 00 50 block 0: first_key " ", block_length 80
1961
+ 65 20 00 51 block 1: first_key "e ", block_length 81
1962
+ 6c 67 00 52 block 2: first_key "lg", block_length 82
1963
+ 72 64 00 4d block 3: first_key "rd", block_length 77
1964
+ ```
1965
+
1966
+ The entries, key followed by its places in relevance order:
1967
+
1968
+ ```
1969
+ block 0 " " 0 " n" 0 "-" 2 "-h" 2 "a" 0 4 "aa" 5
1970
+ "am" 4 5 "an" 0 5 "b" 1 "be" 1 "d" 0 4 "d-" 2
1971
+ "da" 4 5 "de" 0 "ds" 0 "e" 0 1
1972
+ block 1 "e " 0 "ed" 0 "el" 1 "en" 6 3 "er" 0 4 "et" 0
1973
+ "g" 1 "gi" 1 "h" 0 2 "he" 0 "ho" 2 "i" 1
1974
+ "ie" 1 "iu" 1 "l" 0 1 "la" 0 2
1975
+ block 2 "lg" 1 "ll" 2 "m" 1 4 "ms" 4 "n" 0 5 "nd" 0 5
1976
+ "ne" 0 "no" 2 "nt" 6 3 "o" 2 "ol" 2 "oo" 2
1977
+ "or" 2 "p" 6 3 "pe" 6 3 "r" 0 4
1978
+ block 3 "rd" 4 2 "rl" 0 "rp" 6 3 "s" 0 4 "st" 4 "t" 0 4
1979
+ "te" 4 "th" 0 "tw" 6 3 "u" 1 "um" 1 "w" 6 3
1980
+ "we" 6 3 "z" 5 "za" 5
1981
+ ```
1982
+
1983
+ Block 0 is stored as these 80 bytes:
1984
+
1985
+ ```
1986
+ 20 00 01 00 20 6e 00 01 00 2d 00 01 02 2d 68 00 01 02 61 00 02 00 04
1987
+ 61 61 00 01 05 61 6d 00 02 04 05 61 6e 00 02 00 05 62 00 01 01
1988
+ 62 65 00 01 01 64 00 02 00 04 64 2d 00 01 02 64 61 00 02 04 05
1989
+ 64 65 00 01 00 64 73 00 01 00 65 00 02 00 01
1990
+ ```
1991
+
1992
+ Some entries worked through Section B.5 (scores aren't stored, only the
1993
+ ID order they produce, but are given here to show why):
1994
+
1995
+ - `en`: the region `Antwerpen` (ID 3) and the city `Antwerpen` (ID 6)
1996
+ both reach folded tier `10` (a substring match) and need no folding
1997
+ either, so both get the exact spelling bonus, quality `11`; the
1998
+ city's level bonus (`2`) still beats the region's (`1`), giving scores
1999
+ `13` and `12` -- the entry is `6 3`, not in ID order. (Country beating
2000
+ city and region at equal quality is the point of this version's level
2001
+ bonus; city still beats region here exactly as version 1's did, since
2002
+ neither place in this example is a country.)
2003
+ - `h`: the country `Nederland` / `The Netherlands` (ID 0, matching via
2004
+ the `The Netherlands` field) and the region `Noord-Holland` (ID 2)
2005
+ both reach quality `11` the same way `en` does; the country's level
2006
+ bonus (`3`) beats the region's (`1`), giving scores `14` and `12` --
2007
+ the entry is `0 2`. Under version 1's level bonus (city `4`, region
2008
+ `2`, country `1`) this came out the other way, `2 0` -- a region used
2009
+ to outrank a country of equal quality, which this version's bonus
2010
+ ordering specifically fixes.
2011
+ - `ie` and `iu` are both keys of the country `België` / `Belgium` (ID
2012
+ `1`) alone, reached in opposite ways. `ie` exists only in `België`'s
2013
+ folded form (`belgië` does not contain the literal substring `ie`,
2014
+ since its sixth letter is `ë` not `e`, and `belgium` does not contain
2015
+ it either), so it reaches quality `10`, no exact spelling bonus, score
2016
+ `13`; `iu` is a literal substring of `belgium` with no folding
2017
+ involved at all, quality `11`, score `14`. Both entries hold only ID
2018
+ `1`, so the difference isn't visible in the stored bytes, only in how
2019
+ each key was reached.
2020
+ - `nl` is not a key, so a search for `nl` matches nothing, without
2021
+ reading any block beyond the one that would hold it.
2022
+
2023
+ #### B.12.4. Queries
2024
+
2025
+ **`dam`.** Folds to symbols `3, 0, 12`: the one trigram `dam`, list
2026
+ `2364`, a bitmap `30`, places `4` and `5`. Both `Amsterdam` and
2027
+ `Zaandam` contain `dam`, so both are confirmed.
2028
+
2029
+ **`dams`.** Trigrams `dam` (list `2364`, places `4`, `5`) and `ams`
2030
+ (list `354`, place `4`). The intersection is place `4`, `Amsterdam`,
2031
+ whose names do not contain `dams`: it is rejected and the search
2032
+ reports nothing. The lists passed it because a trigram set discards
2033
+ where the trigrams occur: `Amsterdam` has both, just not overlapping as
2034
+ in `dams`.
2035
+
2036
+ **`antwerp`.** Trigrams `ant`, `ntw`, `twe`, `wer`, `erp`, all with
2037
+ bitmap `48` (places `3` and `6`). Both are confirmed, and in relevance
2038
+ order the city (quality `41`, an exact match of the field `Antwerp`
2039
+ needing no folding, score `41 + 2 = 43`) comes before the region
2040
+ (quality `41`, score `41 + 1 = 42`).
2041
+
2042
+ **`belgie`, sorted.** Typed without the diaeresis. Trigrams `bel`,
2043
+ `elg`, `lgi`, `gie`, all list `België`'s country alone (places `1`'s
2044
+ lists -- see B.12.2). `België`'s folded form, `belgie`, equals the
2045
+ query exactly: folded tier `40`. The *unfolded* comparison, `belgië`
2046
+ against `belgie`, does not reach even a substring match (`belgië`
2047
+ does not contain `belgie` literally -- nor does `Belgium`, whose sixth
2048
+ letter is `u`, not `e`), so the exact spelling bonus does not apply:
2049
+ quality stays `40`, score `43`. A reader with no folding at all (version
2050
+ 1, or plain case-insensitive matching) would have found nothing here,
2051
+ since neither field contains `belgie` literally. Querying `belgië`
2052
+ instead (typed correctly) matches `België`'s own field without any
2053
+ folding needed, reaching quality `41`, score `44` -- a query a
2054
+ non-folding reader would also have found, since it's byte-identical to
2055
+ the stored field after lowercasing alone. This reader answers both
2056
+ queries, by folding for the first and plain matching for the second,
2057
+ and ranks the correctly-spelled one slightly higher.
2058
+
2059
+ **`Zaan-dam`.** Folds to `z a a n - d a m`. The trigrams `an-`
2060
+ (list `390`), `n-d` (`10923`), and `-da` (`20468`) are not stored, so
2061
+ nothing can match and no list needs to be read at all: step 3 of
2062
+ Section B.9 ends the search. This is correct, since no name contains
2063
+ `zaan-dam`.
2064
+
2065
+ **`a`, sorted, limit 2.** One code point, and its folded form equals its
2066
+ plain lowercase form (step 1 of Section B.9 applies, per Section B.6's
2067
+ restriction): `a` is in block 0 (the last block whose first key, `" "`,
2068
+ is at most `a`), and its entry is `0 4`, the country `Nederland` (field
2069
+ `Nederland` matches `a` at quality `11`, score `11 + 3 = 14`) ahead of
2070
+ the city `Amsterdam` (quality `11`, score `11 + 2 = 13` -- `Zaandam`
2071
+ ties it but loses the ID tie-break). Under version 1's level bonus this
2072
+ entry was `4 5`, `Amsterdam` and `Zaandam`, since a country was worth
2073
+ less than either city. A search for `a` in ID order, or with a limit
2074
+ above 2, instead compares every name.
2075
+
2076
+ Built in area order instead (`relevance_rule = 1`, from the area bytes
2077
+ of [Section C.8](#c8-worked-example)), the entry of `a` is `0 2`: the
2078
+ country still comes first, then `Noord-Holland`, whose area byte `14`
2079
+ is larger than `Zaandam`'s `5`, while `Amsterdam` has none. That
2080
+ index's `source_checksum` is the one of Section C.8.1,
2081
+ `0xfc0348f51391f7a1`. A reader that ranks by Section B.5's order cannot
2082
+ use that table, and compares every name instead.
2083
+
2084
+ **`ë`, sorted, limit 1.** Its folded form, `e`, differs from its plain
2085
+ lowercase form, `ë` itself, so step 1 does NOT apply here even though
2086
+ `e` is a key (Section B.6) -- comparing against the key `e`'s own
2087
+ precomputed entry (`0 1`, from B.12.3 above) would silently drop the
2088
+ exact spelling bonus `België`'s own `belgië` field earns against the
2089
+ *literal* query `ë`: `belgië` contains `ë`, reaching folded tier `10`
2090
+ *and* the bonus (the raw comparison also reaches tier `10`, since
2091
+ `belgië` literally contains `ë`), quality `11`, score `11 + 3 = 14`.
2092
+ `Nederland` / `The Netherlands` reaches only folded tier `10` with no
2093
+ bonus (neither field contains a literal `ë`), quality `10`, score
2094
+ `10 + 3 = 13`. Scored this way, `België` (`14`) outranks `Nederland`
2095
+ (`13`) outright -- the key `e`'s own precomputed entry, built by
2096
+ scoring `e` (not `ë`) as the query, has them the other way around
2097
+ (`0 1`, `Nederland` first) precisely because `e` itself, being
2098
+ diacritic-free, never earns `België`'s field the bonus the way the
2099
+ literal query `ë` does. Trusting the key's entry here would report
2100
+ `Nederland` as the top match for `ë`, the wrong answer. The query
2101
+ instead falls through to step 2: it folds to one symbol (one short of a
2102
+ trigram), so the lists cannot help either, and every name is compared
2103
+ directly, correctly placing `België` first.
2104
+
2105
+ ### B.13. Qualified Queries
2106
+
2107
+ A search box is often typed into as `Paris, Texas`: a place, then a
2108
+ place it lies in. A reader MAY treat a query that contains a comma
2109
+ (`,`, U+002C) as a **qualified query**, which has several
2110
+ **readings**:
2111
+
2112
+ - the whole query as given, with no contexts, so that a place whose own
2113
+ name contains a comma, such as `Stormont, Dundas and Glengarry
2114
+ Counties`, is still found by typing its name;
2115
+ - for each comma in the query, a reading whose **head** is the text
2116
+ before that comma and whose **contexts** are the parts after it,
2117
+ divided at the remaining commas. White space (Unicode `White_Space`)
2118
+ is removed from both ends of the head and of every context, and
2119
+ contexts that are then empty are dropped, so that `Paris,`, typed on
2120
+ the way to `Paris, Texas`, reads as `Paris`. A reading whose head is
2121
+ empty is dropped, as is one identical to an earlier reading.
2122
+
2123
+ A place matches a reading when its name entry matches the head
2124
+ ([Section B.5](#b5-relevance-order)) and every context matches the name
2125
+ entry of one of the place's ancestors
2126
+ ([Section 7.1](#71-identifiers-and-hierarchy)), each context a further
2127
+ ancestor than the one before it, nearest first: for a city, the first
2128
+ context may match its region or its country, and a second only its
2129
+ country. A reading with more contexts than the place has ancestors does
2130
+ not match it. A place matches a qualified query when it matches any of
2131
+ its readings.
2132
+
2133
+ For ranking, a place's quality is that of the head against its own name
2134
+ entry, and its **context quality** is the sum of the qualities of the
2135
+ contexts against the ancestors they match, under the assignment of
2136
+ contexts to ancestors that gives the highest sum. Among the readings a
2137
+ place matches, the one that ranks first in the order being used counts.
2138
+
2139
+ Every head is matched as a query of its own, so the trigram lists never
2140
+ lose a match of a reading, and a reader uses them head by head
2141
+ ([Section B.9](#b9-query-procedure)). The short-query table is not used
2142
+ for a query with a comma.
2143
+
2144
+ For example, against the file of
2145
+ [Appendix A](#appendix-a-worked-example), `zaandam, noord` has the
2146
+ readings `zaandam, noord` (no contexts), which matches nothing, and
2147
+ `zaandam` with the context `noord`, which matches `Zaandam`, whose
2148
+ region `Noord-Holland` contains `noord`. `antwerp, antwerpen` matches
2149
+ the city `Antwerpen`, whose region is `Antwerpen`, but not the region
2150
+ `Antwerpen`, whose only ancestor is `België`. `zaandam, nederland,
2151
+ noord` matches nothing, since the contexts are nearest first.
2152
+
2153
+ ## Appendix C. Place Location Index
2154
+
2155
+ This appendix defines a **representative cell** for every place, a
2156
+ cell near the middle of the place's area whose centre serves as the
2157
+ place's coordinate, and an **area byte**, the size of that area on a
2158
+ logarithmic scale, and specifies an OPTIONAL sidecar file that stores
2159
+ both. The file is derived entirely from one CGEODATA file and carries
2160
+ file kind `2` ([Section 5](#5-header)).
2161
+
2162
+ ### C.1. Purpose and Properties
2163
+
2164
+ A place search that shows its results on a map, or hands them to an
2165
+ application that wants a coordinate per result, needs a point for each
2166
+ place. The file stores areas, not points, so the point has to be
2167
+ derived from the chunks: [Section C.3](#c3-representative-cell) defines
2168
+ it. Deriving it for one place means decoding every chunk that might
2169
+ hold one of the place's cells, which at worldwide scale is every chunk,
2170
+ about 1.5 seconds. The index described here stores the result for every
2171
+ place, so that finding it costs one read of a few bytes. The area tells
2172
+ an application how far to zoom a map in on the place, and lets a search
2173
+ rank large places before small ones of the same name
2174
+ ([Section B.5.1](#b51-area-order)); computing it is as costly as the
2175
+ cell.
2176
+
2177
+ The index has the following properties:
2178
+
2179
+ - **It is a cache, not a data source.** Every entry is the
2180
+ representative cell, and every area byte the area byte, of
2181
+ [Section C.3](#c3-representative-cell), which a reader can compute
2182
+ from the source file alone. A reader MUST produce the same result with
2183
+ and without the index. The one exception is search ranking: a reader
2184
+ that ranks by area ([Section B.5.1](#b51-area-order)) only while an
2185
+ index supplies the areas orders its search results differently
2186
+ without one, though it finds the same places.
2187
+ - **It is a pure function of its source.** Two writers given the same
2188
+ source file MUST produce byte-identical files. The file carries no
2189
+ timestamp and no parameter chosen by the writer. It is bound to its
2190
+ source by a checksum ([Section C.4](#c4-file-layout)).
2191
+ - **It is uncompressed and fixed-width.** Entry `id` is at a computed
2192
+ offset, so a lookup reads exactly one entry and a reader needs to keep
2193
+ nothing but the header in memory between lookups.
2194
+ - **It is disposable.** It can be rebuilt from its source at any time,
2195
+ and a reader that lacks it computes the same cells from the chunks.
2196
+
2197
+ ### C.2. Entries
2198
+
2199
+ An **entry** names one cell of the source file, or no cell at all. It
2200
+ is an unsigned integer. Let `B = width_exp + height_exp`, so that a
2201
+ chunk index fits in `B` bits. The entry for the cell of depth `d` whose
2202
+ chunk index is `i` ([Section 6.1](#61-chunk-grid)) and whose stored code
2203
+ is `code` ([Section 8.1](#81-cell-grid-and-morton-codes)) is
2204
+
2205
+ ```
2206
+ entry = 2^(B + 2d) + i × 4^d + (code >> 2(D - d))
2207
+ ```
2208
+
2209
+ that is, a single `1` bit (the **marker**), followed by the `B` bits of
2210
+ the chunk index, followed by the cell's `2d`-bit path from the top of
2211
+ the chunk's quadtree. The entry `0` has no marker and means that the
2212
+ place has no cells. A reader decodes a non-zero entry as follows:
2213
+
2214
+ 1. Let `t` be the position of the most significant `1` bit, so that
2215
+ `2^t <= entry < 2^(t+1)`.
2216
+ 2. `t - B` MUST be even, and between `0` and `2D` inclusive. Otherwise
2217
+ the entry is invalid. The depth is `d = (t - B) / 2`.
2218
+ 3. Let `rest = entry - 2^t`. The chunk index is `i = rest >> 2d`, and
2219
+ the stored code is `(rest mod 4^d) << 2(D - d)`.
2220
+
2221
+ Since `rest < 2^(B + 2d)`, the chunk index is always less than
2222
+ `W × H`. The largest entry, for a cell of depth `D`, has
2223
+ `B + 2D + 1` bits, so every entry of a file fits in
2224
+
2225
+ ```
2226
+ entry_width = ceil((width_exp + height_exp + 2 × max_depth + 1) / 8)
2227
+ ```
2228
+
2229
+ bytes, which is what the index uses for all of them. For a `64 × 64`
2230
+ chunk grid this is 4 bytes up to `max_depth = 9`, 5 bytes up to
2231
+ `max_depth = 13`, and 6 bytes up to `max_depth = 17`. A reader whose
2232
+ integers are exact only up to `2^53`, such as one in JavaScript, can
2233
+ handle entries of up to 6 bytes and MAY reject an index with wider
2234
+ ones. The marker is what lets one width serve cells of
2235
+ every depth, and lets `0` stand for no cell without reserving any
2236
+ valid cell's value.
2237
+
2238
+ Writers following this version store only full-precision cells
2239
+ (`d = D`), as [Section C.3](#c3-representative-cell) requires. Readers
2240
+ MUST nevertheless accept an entry of any depth, so that a later version
2241
+ can name coarser cells without a new layout.
2242
+
2243
+ ### C.3. Representative Cell
2244
+
2245
+ The **area** of a place is the set of records, across all chunks,
2246
+ attributed to that place or to a place under it: for a city, the
2247
+ records whose palette entry is the city; for a region, those of the
2248
+ region and of its cities; for a country, those of the country, its
2249
+ regions, and their cities ([Section 7.1](#71-identifiers-and-hierarchy)).
2250
+ Records with palette index `0` belong to no area. A place whose area is
2251
+ empty has no representative cell, and its entry is `0`.
2252
+
2253
+ Each record of the area is placed on the global grid of full-precision
2254
+ cells used by the lookup procedure ([Section 9](#9-lookup-procedure),
2255
+ step 2). For a record with stored code `code` and depth `d` in chunk
2256
+ `i = r × W + c`, let `(x, y)` be the cell whose full-precision code is
2257
+ `code`, the south-west corner cell of the record. Then the record
2258
+ covers the `s × s` square of global cells with south-west corner
2259
+ `(gx, gy)`, where
2260
+
2261
+ ```
2262
+ gx = c × 2^D + x gy = r × 2^D + y s = 2^(D - d)
2263
+ ```
2264
+
2265
+ and it has **weight** `s × s`, its area in full-precision cells. The
2266
+ representative cell is computed from these squares in four steps.
2267
+
2268
+ 1. **Centres.** The centre of each square, in units of half a cell, is
2269
+ `u = 2 × gx + s` horizontally and `v = 2 × gy + s` vertically. Both
2270
+ are integers.
2271
+ 2. **Weighted median per axis.** Let `T` be the total weight of the
2272
+ area. For the `u` axis, let `lo` be the smallest centre `u` for which
2273
+ the weight of all squares with centre at most `u` is at least `T / 2`.
2274
+ If that weight is exactly `T / 2`, let `hi` be the smallest centre
2275
+ greater than `lo`, which exists because the remaining weight is
2276
+ positive. Otherwise let `hi = lo`. The median lies at `(lo + hi) / 2`
2277
+ half-cells, in the full-precision cell column
2278
+
2279
+ ```
2280
+ fx = floor((lo + hi) / 4)
2281
+ ```
2282
+
2283
+ The same procedure on the `v` centres gives the row `fy`. With equal
2284
+ weights this is the familiar median: the middle value of an odd
2285
+ count, and the midpoint of the two middle values of an even one.
2286
+ 3. **Nearest cell of the area.** For every square, its cell nearest to
2287
+ `(fx, fy)` is `(clamp(fx, gx, gx + s - 1), clamp(fy, gy, gy + s - 1))`,
2288
+ at offset `(dx, dy)` from `(fx, fy)`. Its squared distance is
2289
+
2290
+ ```
2291
+ (a × dx)^2 + (b × dy)^2 where g = min(2 × H, W), a = 2 × H / g, b = W / g
2292
+ ```
2293
+
2294
+ which is proportional to the squared distance in degrees, a
2295
+ full-precision cell being `360 / (W × 2^D)` degrees wide and
2296
+ `180 / (H × 2^D)` high. The representative cell is the nearest of
2297
+ these cells. Among equally near cells, it is the one in the lower
2298
+ row, and among those, the one in the lower column. When `(fx, fy)`
2299
+ itself lies in the area, it is the only cell at distance `0`, and so
2300
+ it is the representative cell.
2301
+ 4. **Entry.** The representative cell `(px, py)` is the full-precision
2302
+ cell `x = px mod 2^D`, `y = py mod 2^D` of chunk
2303
+ `i = (py >> D) × W + (px >> D)`, and its entry is formed as in
2304
+ [Section C.2](#c2-entries) with `d = D`.
2305
+
2306
+ The representative cell always lies within one of the area's records,
2307
+ so a lookup ([Section 9](#9-lookup-procedure)) of any point in it, in
2308
+ particular its centre, resolves to the place or to a place under it.
2309
+ The result depends only on the set of records in the area, not on the
2310
+ order in which they are visited.
2311
+
2312
+ The **area byte** of a place is `0` when its area is empty. Otherwise it
2313
+ is the number of binary digits of `T^4`, where `T` is the total weight
2314
+ of step 2, but at most `255`:
2315
+
2316
+ ```
2317
+ area_byte = min(255, floor(log2(T^4)) + 1)
2318
+ ```
2319
+
2320
+ Each step is a quarter of a doubling: an area of `T` cells has area byte
2321
+ `v` when `2^((v - 1) / 4) <= T < 2^(v / 4)`, so a reader can recover the
2322
+ area to within about 9%. Implementations MUST compute it exactly, for
2323
+ example by counting the bits of `T^4` in integer arithmetic, since a
2324
+ floating-point logarithm can round the wrong way for an area just below
2325
+ a power of two. A `128 × 128` chunk grid with `max_depth = 10` has
2326
+ `2^34` full-precision cells, area byte `137`; the cap of `255` is only
2327
+ reached by an area of `2^63.5` cells or more.
2328
+
2329
+ Every quantity above is an integer, and implementations MUST compute
2330
+ them exactly. The largest is a squared distance, which is less than
2331
+ `(a × W × 2^D)^2 + (b × H × 2^D)^2`; an implementation whose integers
2332
+ are exact only up to `2^53`, such as one in JavaScript, SHOULD check
2333
+ this bound before computing any representative cell. It holds for a
2334
+ `64 × 64` chunk grid up to `max_depth = 19`.
2335
+
2336
+ Informally: the median locates the middle of the place along each axis
2337
+ independently, weighting every cell by its area. Unlike the mean, it is
2338
+ not dragged away by a distant exclave or island. Unlike the centre of
2339
+ the bounding box, it follows where the area actually is. When the
2340
+ median point falls outside the place, as it can for a crescent-shaped
2341
+ area or one made of several islands, step 3 moves it to the nearest
2342
+ cell that is inside. Two known imperfections follow from working on
2343
+ the grid: weights are areas in degrees, not on the ground, so cells at
2344
+ high latitude count for more than their true size, in the area byte as
2345
+ much as in the median; and the horizontal
2346
+ axis does not wrap, so the median of a place that straddles the 180th
2347
+ meridian lands on one side of it rather than in the middle.
2348
+
2349
+ ### C.4. File Layout
2350
+
2351
+ The file is one header followed by the entries and the area bytes,
2352
+ with no padding and no trailer.
2353
+
2354
+ | Field | Type | Description |
2355
+ |-------------------|------------------------------|-------------|
2356
+ | `signature` | 8 bytes | The ASCII bytes `CGEODATA`, as in [Section 5](#5-header). |
2357
+ | `version` | varint | Kind and version as defined in Section 5. This appendix specifies kind `2`, version `1`, so the value is `33` (`21`). Version `0` had no `areas`; readers MUST reject it. |
2358
+ | `source_checksum` | u64 | Checksum of the start of the source file, defined below. |
2359
+ | `entry_width` | u8 | The width in bytes of every entry. MUST equal the value given in [Section C.2](#c2-entries) for the source's header. |
2360
+ | `place_count` | varint | `N`, the number of places in the source ([Section 7.1](#71-identifiers-and-hierarchy)). |
2361
+ | `entries` | `N × entry_width` bytes | The entry of place `0`, then of place `1`, and so on, each an unsigned little-endian integer of `entry_width` bytes. |
2362
+ | `areas` | `N` bytes | The area byte ([Section C.3](#c3-representative-cell)) of place `0`, then of place `1`, and so on. |
2363
+
2364
+ The file length MUST be exactly the header length plus
2365
+ `N × (entry_width + 1)`. The entry of place `id` starts at byte
2366
+ `header_length + id × entry_width`, and its area byte is at
2367
+ `header_length + N × entry_width + id`. The area bytes follow the
2368
+ entries rather than being part of them so that a reader ranking a
2369
+ search by area reads all of them in one read.
2370
+
2371
+ `source_checksum` is the 64-bit FNV-1a hash
2372
+ ([Section B.8](#b8-source-checksum)) of the first bytes of the source
2373
+ file up to, but not including, the first chunk: the header, the
2374
+ directory, and the place table, that is file offsets `0` to
2375
+ `chunks_start - 1` ([Section 6.3](#63-locating-a-chunk)). It is stored
2376
+ least significant byte first.
2377
+
2378
+ The index depends on the chunks as well as on the place table, so the
2379
+ checksum of [Section B.8](#b8-source-checksum), which covers only the
2380
+ place table, would not do. Hashing the chunks themselves would make
2381
+ loading an index read the whole source file. The directory is a
2382
+ compromise: it holds the length of every compressed chunk, which
2383
+ changes whenever the chunk's content does, except in the unlikely case
2384
+ that a rebuilt chunk compresses to exactly its old length. Writers that
2385
+ rebuild a source SHOULD rebuild its index at the same time rather than
2386
+ rely on the checksum to catch the difference.
2387
+
2388
+ Readers SHOULD compute the checksum when they load an index, and a
2389
+ reader that does so MUST reject an index whose `source_checksum`
2390
+ differs from it. A reader that rejects an index falls back to computing
2391
+ representative cells from the chunks.
2392
+
2393
+ ### C.5. Lookup Procedure
2394
+
2395
+ To find the representative coordinate of place `id` with an index:
2396
+
2397
+ 1. **Validate.** `id` MUST be less than `N`.
2398
+ 2. **Read the entry.** Read `entry_width` bytes at
2399
+ `header_length + id × entry_width` and interpret them as an unsigned
2400
+ little-endian integer.
2401
+ 3. **Decode** it as in [Section C.2](#c2-entries). An entry of `0`
2402
+ means the place has no representative cell, and no coordinate.
2403
+ 4. **Compute the coordinate.** The cell's extent follows from its chunk
2404
+ ([Section 6.1](#61-chunk-grid)) and its path within the chunk
2405
+ ([Section 8.1](#81-cell-grid-and-morton-codes)), as for any record.
2406
+ The place's coordinate is the centre of that extent.
2407
+ 5. **Read the area**, if wanted: the byte at
2408
+ `header_length + N × entry_width + id`.
2409
+
2410
+ Without an index, a reader computes the same cell and area byte from the
2411
+ chunks by [Section C.3](#c3-representative-cell) and continues at
2412
+ step 4.
2413
+
2414
+ A place of area byte `v` covers about `2^((v - 0.5) / 4)` full-precision
2415
+ cells, each `360 / (W × 2^D)` degrees wide and `180 / (H × 2^D)` high.
2416
+ A square of the same area in degrees is a rough guide to how far to zoom
2417
+ a map in on the place: at zoom `z`, a Web Mercator map shows
2418
+ `360 / 2^z` degrees of longitude across one 256-pixel tile.
2419
+
2420
+ The extent of the cell tells a reader how precisely to present the
2421
+ coordinate: a full-precision cell of a worldwide file with
2422
+ `max_depth = 8` is about `0.02°` wide, so three decimals are
2423
+ meaningful and more are not.
2424
+
2425
+ ### C.6. Robustness
2426
+
2427
+ A locate index may come from an untrusted source, or may be stale.
2428
+ Readers MUST NOT assume that it is well formed or that it matches its
2429
+ source.
2430
+
2431
+ - Readers MUST verify the signature, kind, and version before
2432
+ interpreting any other field.
2433
+ - Readers MUST check that `entry_width` equals the value
2434
+ [Section C.2](#c2-entries) gives for the source, that `place_count`
2435
+ equals `N`, and that the file length is exactly the header length
2436
+ plus `N × (entry_width + 1)`, before reading any entry.
2437
+ - Every byte is a valid area byte, so there is nothing to check. A
2438
+ wrong one only misorders search results ranked by area or misjudges a
2439
+ zoom level.
2440
+ - Readers MUST reject an entry whose marker is not at a valid position
2441
+ ([Section C.2](#c2-entries), step 2). The decoding cannot produce a
2442
+ chunk index outside the grid, so no further bounds check is needed
2443
+ before computing the cell's extent.
2444
+ - Unlike a search index, a locate index contributes its result directly:
2445
+ a malformed or mismatched index yields a wrong coordinate rather than
2446
+ a missed one. A reader that cannot trust the pairing MAY confirm a
2447
+ result by looking up its coordinate and checking that it resolves to
2448
+ the place or to a place under it, at the cost of decoding one chunk.
2449
+
2450
+ ### C.7. Design Notes
2451
+
2452
+ This section is informative.
2453
+
2454
+ **Measurements.** On a worldwide file of 319,440 places with a
2455
+ `64 × 64` chunk grid and `max_depth = 8` (9.5 MiB), entries are 4 bytes
2456
+ and the index (of version `0`, without area bytes) is 1.2 MiB; the area
2457
+ bytes add one byte per place, 0.3 MiB. Building it decodes the chunks two or three
2458
+ times, since places are processed a batch of countries at a time to
2459
+ bound memory, and takes about 11 seconds. Without the index, one representative cell
2460
+ costs about 1.6 seconds, nearly all of it spent decoding chunks. With
2461
+ it, a lookup takes well under a millisecond, even with the file evicted
2462
+ from the operating system's cache, and a reader that is idle between
2463
+ lookups holds nothing but an open file. An older worldwide build at
2464
+ `max_depth = 11` (67 MiB, 255,555 places) needs 5-byte entries, for an
2465
+ index of 1.2 MiB built in 2.5 minutes. A `128 × 128` grid with
2466
+ `max_depth = 10` (71 MiB, 259,598 places) also needs 5-byte entries;
2467
+ with its area bytes the index is 1.5 MiB, built in about 90 seconds,
2468
+ of which totalling the areas takes a few.
2469
+
2470
+ **Alternatives measured.** Storing only the chunk of each place's cell
2471
+ (2 bytes per place for a `64 × 64` grid) and decoding that chunk at
2472
+ lookup time cost 4 to 6 ms per lookup, and about 50 ms for a burst of
2473
+ ten, the typical page of search results; the time goes into decoding
2474
+ the chunk, not reading it. With `max_depth = 11`, where chunks are
2475
+ about ten times larger, it would cost tens of milliseconds per lookup.
2476
+ Compressing the entries in blocks of 256 saved 30% of the size and
2477
+ doubled the lookup time, since the cells of neighbouring places are
2478
+ close but their low-order bits are not. Storing a coarser cell to save
2479
+ bytes and refining it from the chunk at lookup time has the costs of
2480
+ the chunk-only design for every place whose cell is deeper than the
2481
+ coarse cell. Fitting 4-byte entries at `max_depth = 11` means coarsening
2482
+ every cell deeper than depth 9, which was 16% of places, with chunk
2483
+ decodes of 40 to 140 ms each.
2484
+
2485
+ **Why the whole area.** The records attributed directly to a region or
2486
+ country are only the parts not covered by any of its children: often
2487
+ nothing at all, and otherwise leftover strips such as water or
2488
+ unincorporated land. On the worldwide file, 41% of regions have no
2489
+ records of their own. Including the records of every place under a
2490
+ place makes the coordinate of a region or country the middle of the
2491
+ region or country, as a user expects.
2492
+
2493
+ ### C.8. Worked Example
2494
+
2495
+ This example indexes the source file of
2496
+ [Appendix A](#appendix-a-worked-example). There, `B = 1 + 1 = 2` and
2497
+ `D = 2`, so entries have at most `2 + 4 + 1 = 7` bits and
2498
+ `entry_width = 1`. The file is `19 + 7 = 26` bytes.
2499
+
2500
+ #### C.8.1. File (33 bytes)
2501
+
2502
+ ```
2503
+ 43 47 45 4f 44 41 54 41 signature "CGEODATA"
2504
+ 21 version 33 -> kind 2 (place location index), version 1
2505
+ a1 f7 91 13 f5 48 03 fc source_checksum 0xfc0348f51391f7a1
2506
+ 01 entry_width 1
2507
+ 07 place_count 7
2508
+ 73 00 73 00 00 74 00 entries of places 0 to 6
2509
+ 0e 00 0e 00 00 05 00 areas of places 0 to 6
2510
+ ```
2511
+
2512
+ The checksum is the FNV-1a 64 hash of the first 131 bytes of the
2513
+ Appendix A file: the 17-byte header, the 5-byte directory, and the
2514
+ 109-byte place table, up to the first byte of chunk `3` at offset
2515
+ `131`.
2516
+
2517
+ #### C.8.2. Areas
2518
+
2519
+ All records are in chunk `3` (`c = 1`, `r = 1`), so `gx = 4 + x` and
2520
+ `gy = 4 + y`. The four records with a place are:
2521
+
2522
+ | Record | Code, depth | Place | `(gx, gy)` | `s` | Weight | `u` | `v` |
2523
+ |--------|-------------|------------------|------------|-----|--------|------|------|
2524
+ | 0 | 0, 1 | 2, Noord-Holland | (4, 4) | 2 | 4 | 10 | 10 |
2525
+ | 1 | 4, 2 | 5, Zaandam | (6, 4) | 1 | 1 | 13 | 9 |
2526
+ | 5 | 8, 1 | 2, Noord-Holland | (4, 6) | 2 | 4 | 10 | 14 |
2527
+ | 6 | 12, 2 | 5, Zaandam | (6, 6) | 1 | 1 | 13 | 13 |
2528
+
2529
+ Records `2` to `4` have palette index `0`. The area of Zaandam (`5`) is
2530
+ records `1` and `6`. The areas of Noord-Holland (`2`) and of Nederland
2531
+ (`0`), which contains it, are all four records. Amsterdam, België, and both
2532
+ Antwerpens have no records, so their entries are `00`.
2533
+
2534
+ #### C.8.3. Zaandam
2535
+
2536
+ `T = 2`. Both `u` centres are `13`, which already holds more than half
2537
+ the weight, so `lo = hi = 13` and `fx = floor(26 / 4) = 6`. The `v`
2538
+ centres are `9` and `13`, one weight each. The weight at or below `9`
2539
+ is exactly `T / 2`, so `lo = 9`, `hi = 13`, and
2540
+ `fy = floor(22 / 4) = 5`: the median falls midway between Zaandam's two
2541
+ cells.
2542
+
2543
+ Cell `(6, 5)` is local cell `(2, 1)` of chunk `3`, code `6`, which is
2544
+ record `3`, with no place. The nearest cells of the area are record
2545
+ `1`'s `(6, 4)` and record `6`'s `(6, 6)`, both one row away. With
2546
+ `g = min(4, 2) = 2`, `a = 2` and `b = 1`, both are at squared distance
2547
+ `1`. The tie goes to
2548
+ the lower row, `(6, 4)`: local cell `(2, 0)` of chunk `3`, code `4`.
2549
+ The entry is `2^(2 + 4) + 3 × 16 + 4 = 116`, `74`.
2550
+
2551
+ Its centre is `lat -90 + 4.5 × 22.5 = 11.25`,
2552
+ `lon -180 + 6.5 × 45 = 112.5`, which is the cell of the first lookup in
2553
+ [Section A.5](#a5-lookups), Zaandam.
2554
+
2555
+ #### C.8.4. Noord-Holland and Nederland
2556
+
2557
+ `T = 4 + 1 + 4 + 1 = 10`. The `u` centres are `10` with weight `8`
2558
+ and `13` with weight `2`: `10` holds more than half, so
2559
+ `fx = floor(20 / 4) = 5`. The `v` centres are `9` (weight `1`), `10`
2560
+ (`4`), `13` (`1`), and `14` (`4`). The weight at or below `10` is `5`,
2561
+ exactly half, so `lo = 10`, `hi = 13`, and `fy = floor(23 / 4) = 5`.
2562
+
2563
+ Cell `(5, 5)` is local cell `(1, 1)`, inside record `0`'s square, so it
2564
+ is the representative cell. Its code at depth `2` is `3`, and the
2565
+ entry is `64 + 48 + 3 = 115`, `73`. Its centre is `lat 33.75`,
2566
+ `lon 67.5`, where a lookup finds record `0`: Noord-Holland, which is
2567
+ the place itself for ID `2` and a place under it for ID `0`.
2568
+
2569
+ #### C.8.5. Decoding
2570
+
2571
+ Entry `74` is `116`. Its most significant bit is `t = 6`, and
2572
+ `t - B = 4` is even and at most `2D = 4`, so `d = 2`.
2573
+ `rest = 116 - 64 = 52`, the chunk index is `52 >> 4 = 3`, and the
2574
+ stored code is `52 mod 16 = 4`. An entry of `75` (`117`) would decode
2575
+ the same way to code `5`, a cell with no place: a well-formed entry is
2576
+ not necessarily a correct one, which is what the checksum is for. An
2577
+ entry of `20` (`32`) would be rejected, since `t - B = 3` is odd.
2578
+
2579
+ #### C.8.6. Area Bytes
2580
+
2581
+ Zaandam's area has `T = 2` (C.8.3). `T^4 = 16`, `10000` in binary, has
2582
+ five digits, so its area byte is `05`: `2^(4/4) <= 2 < 2^(5/4)`.
2583
+ Noord-Holland's and Nederland's have `T = 10` (C.8.4). `T^4 = 10000` lies
2584
+ between `2^13 = 8192` and `2^14 = 16384`, so it has fourteen binary
2585
+ digits and their area byte is `0e`. The four places without records
2586
+ have area byte `00`.
2587
+
2588
+ A full-precision cell of this file is `45°` wide and `22.5°` high,
2589
+ `1012.5` square degrees. Area byte `05` stands for about
2590
+ `2^(4.5 / 4) × 1012.5 ≈ 2209` square degrees, against Zaandam's true
2591
+ `2025`.
2592
+
2593
+ ## Appendix D. References
2594
+
2595
+ - [LZMA] Pavlov, I., "LZMA SDK", https://www.7-zip.org/sdk.html: the
2596
+ range coder of `LzmaDec.c`, with `kNumBitModelTotalBits` 11 and
2597
+ `kNumMoveBits` 5 where this format uses 12 and 4.
2598
+ - [RFC1950] Deutsch, P. and J-L. Gailly, "ZLIB Compressed Data Format
2599
+ Specification version 3.3", May 1996.
2600
+ - [RFC1951] Deutsch, P., "DEFLATE Compressed Data Format Specification
2601
+ version 1.3", May 1996.
2602
+ - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
2603
+ Requirement Levels", BCP 14, March 1997.
2604
+ - [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 10646",
2605
+ STD 63, November 2003.
2606
+ - [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119
2607
+ Key Words", BCP 14, May 2017.
2608
+ - Protocol Buffers, "Encoding: Base 128 Varints",
2609
+ <https://protobuf.dev/programming-guides/encoding/#varints>.
2610
+ - Morton, G. M., "A computer oriented geodetic data base and a new
2611
+ technique in file sequencing", IBM, 1966.
2612
+ - [UAX15] Whistler, K., "Unicode Normalization Forms", Unicode Standard
2613
+ Annex #15, <https://unicode.org/reports/tr15/>.
2614
+ - [UNICODE] The Unicode Consortium, "The Unicode Standard", Section
2615
+ 3.13 "Default Case Algorithms", <https://www.unicode.org/versions/latest/>.
2616
+ - [FNV] Eastlake, D., Fowler, G., Noll, L., Vo, K-P., and T. Hansen,
2617
+ "The FNV Non-Cryptographic Hash Algorithm",
2618
+ draft-eastlake-fnv, <https://datatracker.ietf.org/doc/draft-eastlake-fnv/>.
2619
+ - [history.md](https://github.com/ferrybig/loc-to-city/blob/master/history.md): the prototype and measurements this format
2620
+ is derived from.