eeuz fea Place Name Gazetteer - krcenov/RNS510-Map-Viewer GitHub Wiki
eeuz.fea β Place-Name Gazetteer
Status: π‘ Partially cracked Β· 553 MB Β· FEATURE_COMPRESSED
(compressionType 3 β a different directory encoding from MAP_COMPRESSED,
despite sharing the same 80-byte header and zlib-stream-packing shell) Β·
4 of the file's directory tables now located and validated (T1βT4). A
still later session disassembled real DBAL.OUT firmware code (not
just symbol names) and fully cracked the relative point-geometry
encoding β a real getCoordinates() function, cumulative 16-bit
delta-chain, scaled by per-layer factors β but found strong, direct
disassembly evidence that the absolute anchor a chain is positioned
against is never supplied by this file's own code at all; see "Cracked
via real DBAL.OUT disassembly" below for the full picture and why this
means per-entry coordinates may not be recoverable from .fea bytes
alone.
This is the file that answers "why has no cracked road tile ever shown a lake, river, park, or coastline" β it's not road/water-polygon geometry at all.
What it contains (confirmed)
A general multi-language named-place gazetteer: cities/towns/villages at every scale, named water bodies (Mediterranean, Black, Baltic, North, Caspian Seas; Gulf of Bothnia), islands (the whole Greek archipelago), and β not part of the original hypothesis β road/route shield labels (European route numbers E50/E58/..., national route codes R22/A375/M4/..., Asian Highway numbers AH30/AH61/...). None of the already-cracked road-geometry files carry this content.
Container
Same 80-byte (*$SIEMENS&^)/Copyright 1998 header as MAP_COMPRESSED,
then an ~11.7MB directory region (byte 80 β file offset 11,727,784), then
standard RFC1950 zlib streams packed back-to-back to EOF β chaining
verified byte-exact across thousands of consecutive entries, with
occasional small non-zlib "gaps" between entries (not understood; skipped
via local brute-force re-scan, which works reliably).
Entry content
Unrelated to MAP_COMPRESSED's tile schema (no 0x0146 magic, no
anchor+delta blocks). Entries are much smaller than tiles (42β63,348
bytes decompressed, mean ~380 bytes) and pack multiple small sub-records.
Most are compact, near-identical "stub" placeholder records; a minority
carry a multi-language name table:
[1-byte language id][1-byte UTF-8 length][UTF-8 name bytes], repeated
once per language (20β26 languages for a major place).
Validated: an entry decodes a 26-language name table unambiguously
"Mediterranean Sea" in every language on the disc's market. A wide scan
(11 sample windows across the whole file, 33,628 entries, 922 with a
decodable name) found hundreds more real matches, including a IaΘi,
Romania entry decoding IASI, JASY, IASIO, JΓSZVΓSΓR, JASSY, YASSY, YAS β
every one a genuine historical/foreign exonym for that same real city
already validated via eeu.rd and
eeu.cty.
The directory format β cracked (12-byte big-endian offset/length index)
The ~11.7MB directory region divides exactly into 977,308 fixed 12-byte
records plus an 8-byte trailer. The crack: each record is 3
big-endian uint32 fields β (offset, declen, complen) β a keyed
index into the file's own zlib entries, NOT little-endian and NOT a
simple sequential/spatial array. Validated at scale: a dense 1,191-record
run scores 1,008/1,191 (84.7%) exact byte-for-byte decompression-and-
length matches; a random 5,000-record sample scores 1,478/5,000 (29.6%);
searching for the LITERAL (offset, declen, complen) of 4 independently-
verified real places (Mediterranean Sea, IaΘi, Bratislava, Nisyros) finds
an exact, correctly-ordered 12-byte match every time. Two field-order
variants exist ([declen,complen,offset] and [offset,declen,complen])
β a rotation, not a different encoding.
This is a hash/keyed index, not a spatial or sequential table: 42.7% of consecutive records are byte-identical (collision/padding runs), only 57% of values are distinct, and a directory table can index an entry far outside its own physical byte range (one table at 306β311MB indexes an entry at 363MB).
Also found: this same 12-byte-record directory shape recurs inside
the payload too β a full-file enumeration hit a 5,001,156-byte gap
(exactly 416,763 Γ 12 + 0) with the identical structural signature,
most likely marking a section/region boundary. So this file is not
[header][one directory][one payload run] β it embeds several more
directory-shaped regions mid-payload (see the next section β 2 more were
found and confirmed).
A later session: tables T3 and T4 found β resolves Turku/Trondheim/Oslo completely
The open item above (3 test cities β Turku, Trondheim, Oslo, all
~550MB β had no record in either known table, evidence of at least one
more unlocated directory region) is now resolved. A whole-file
stride-12 self-similarity scan (arr[:-12] == arr[12:], blocked and
averaged with numpy β a few seconds over the whole 553MB file, far
faster than sequential entry-by-entry walking) located every
directory-shaped region in one pass:
| Table | Byte range | Density | Records |
|---|---|---|---|
| T1 (known) | 80 β 11,800,000 | ~0.865 | 977,308 |
| T2 (known) | 306,200,000 β 311,200,000 | ~0.838 | 416,763 |
| T4 (new) | 529,687,345 β 529,889,749 | ~0.75 | 16,867 |
| T3 (new) | 546,882,678 β 547,158,126 | ~0.63β0.79 | 22,954 |
Both new tables share T1/T2's exact structure β real zlib-entry chain
walking confirms a genuine non-payload gap at each, with a real zlib
header resuming immediately after β plus a small twist: each starts with
an undecoded 6-byte prefix before its 12-byte-aligned records begin
(gap_len - 6 divides evenly by 12 for both). Both verify at HIGH rates
with the existing decode_directory_table()/verify_index_triple()
machinery, no new code needed: T3: 17,107/22,954 (74.5%), T4:
9,968/16,867 (59.1%) β both well above T1's own average (2.7%β73.5%
per block).
Direct resolution: the payload immediately following T3 contains
Turku (offset 550,612,987), Trondheim (550,725,854), and Oslo
(550,550,064) β the exact 3 cities confirmed absent from T1/T2.
find_index_record_for_offset() against T3 alone finds all 3
immediately, and the found (declen, complen) fields match a REAL
decompression at each city's own offset EXACTLY, 3/3, both fields β
Turku (16,028/10,596), Trondheim (34,972/24,283), Oslo (40,665/28,358),
no tolerance needed. This was never a hole in the offset/declen/complen
model, just an unlocated table.
A 5th, weaker candidate at the very end of the file (~551.16MβEOF, where real zlib chaining genuinely stops for good) was also found by the same scan but does NOT verify cleanly at any byte phase tried (best: 3.4%, vs. 59β75% for T3/T4) β left as an honest, low-confidence lead, not claimed as a validated 5th table.
What's NOT cracked
- Per-record ABSOLUTE coordinates. Exhaustive scans for a plausible
embedded lon/lat pair, and for an embedded pointer to the same place's
eeu.ctyself-index (14 encodings Γ 6 independent real cities, all zero hits, plus a directory-wide check) β both directly refuted, not just unconfirmed. Now backed by a direct disassembly reason why: see "Cracked via real DBAL.OUT disassembly" below βFeaCoordReceiverInternal::getCoordinates()'s own accumulators are proven (by itsinit()code) to always start at (0, 0); the RELATIVE delta-chain format feeding them is fully cracked, but no absolute anchor is ever supplied anywhere in this file's own decode path. A.feaentry can currently only be geolocated via its embedded name (cross-referenced against real-world geography oreeu.cty), not a stored position. - How many directory/section-boundary regions exist in total β 4 are now confirmed (T1/T2/T3/T4) plus a 5th weaker, unconfirmed candidate at EOF β and what the small non-directory-shaped non-zlib gaps between ordinary entries actually are.
A later session's new lead: eeu.mod's own schema, in tension with the hash-table finding
eeu.mod's feature block (never checked
against eeuz.fea specifically before) is the single largest in the
whole schema β ~77 real fields, describing:
MapHeader{db_cover bbox, parcel_width/height/cnt_x/cnt_y/norm_x/norm_y grid,
feaType, scaleCnt, scales[]}
-> ParcelHeader{offset, byteCnt, byteCntZip} -- 12 bytes!
-> FeatureDataHeader{category, type, flags, feaPointCnt, ...}
[geometry variant: line | poly | point | road, each with delta_long/delta_lat]
ParcelHeader{offset, byteCnt, byteCntZip} independently confirms and
names the already-cracked 12-byte directory triple above β found two
different ways in the same session (offset=offset, byteCnt=declen,
byteCntZip=complen).
Tested and refuted: the schema's parcel_cnt_xΓparcel_cnt_y
product, on the guess it should equal the directory's own 977,308-record
count β 977,308 = 929 Γ 1,052 β neither value appears anywhere as a
uint32 (either endianness) in the first 12MB of the file.
The single most actionable new lead, not yet tested: the schema
names delta_long/delta_lat as real per-geometry-point fields β
coordinates in this format are RELATIVE deltas, not absolute values,
directly explaining why the exhaustive absolute-coordinate search above
found nothing. A future session should search for a small delta pair
near an anchor (a parcel's own coordinate, or eeu.cty's already-known
real position for that place) rather than a standalone absolute value.
This is a genuine, unresolved tension, not a resolved contradiction:
the schema's parcel-grid/delta-coordinate design sits uneasily next to
the independently well-evidenced "hash table, no locatable coordinate"
finding above. Possible reconciliations, none tested: this disc's build
may use only a subset of the schema's full generality (matching the
pattern seen elsewhere, e.g. eeuz.pca's
always-zero clusterOffset/clusterCount) β note that T3/T4 (found and
confirmed above, including the Turku/Trondheim/Oslo table) show the same
offset/declen/complen index-triple shape as T1/T2, not a grid/delta-
coordinate one, so this reconciliation option remains open rather than
resolved; or the entries tested so far (Mediterranean Sea, IaΘi, ...) may
be a type/category that doesn't carry the point/road geometry
sub-structure at all.
A still later session's first concrete attempt, inconclusive β mild
new evidence toward the last reconciliation above: located IaΘi's own
name table precisely inside its 15,687-byte entry (byte 1336) and
inspected the 20 bytes immediately before it β the natural place for a
FeatureDataHeader/geometry block. Naively read as category/type/ flags/feaPointCnt, the 4th byte is 7 β implausible for a single city
label (should be a 1-point feature) β and no small int16 value in that
window resembles a plausible coordinate delta. Doesn't refute the
delta-coordinate theory (the anchor position was a guess, not derived
from the schema), but is a real data point against "IaΘi's geometry
sits directly adjacent to its name table," and toward "this entry may
not carry point geometry for IaΘi at all." A proper test needs an
actual sub-record walker (respecting feaPointCnt-driven variable
lengths), not yet built.
Cracked via real DBAL.OUT disassembly: the relative point-geometry format β and strong evidence the absolute anchor lives outside this file's own code entirely
A still later session went beyond debug-string name matching and
actually disassembled real firmware code, the same technique that
cracked eeu.iof's type field:
dbal/V010_015/DBAL.OUT is a small, UNLINKED ET_REL PowerPC object with
every function's full machine code physically present in the file (no
FHDD6.FLI-style disassembly wall) β used capstone (PowerPC,
big-endian) plus a hand-rolled ELF32 BE section/symbol/relocation
table parser (the relocation table is what makes this session's result
trustworthy β it resolves every lis/addi global-address pair to its
REAL linker symbol name, removing the guesswork that address-only
disassembly would otherwise require).
A real, dedicated db_feature.cpp handler, with real class names
String-mining DBAL.OUT (beyond the db_intersection* strings already
documented for eeu.iof) found a dedicated handler for this exact file:
db_fea_init_V005, db_fea_get_file_header_V005,
db_fea_read_parcels_V005, db_fea_get_layer_properties_V005, etc., all
in db_feature.cpp. Relocation-table resolution of the functions these
call turned up real, internal C++ class and type names never seen before
in this project: FeaRequest, FeaDataReceiver, FeaCoordReceiverInternal
(with a vtable, _vt$24FeaCoordReceiverInternal), FeaLayerPropertiesInternal,
LocalPoint, FeaCrossOver, and a nested
FeaCoordReceiverInternal::ThinoutAccuracy enum β plus
parseExtractedParcel__FPUcR15FeaDataReceiverR10FeaRequestT0i ("parse
extracted parcel"), the real per-entry content parser, and
getFeatureName__FUcPUcT1Ri ("get feature name" β the real function
behind this project's own scan_names()), DBTransCodeChecker (text
validation), and tt_ara/tt_rus (translation tables β confirming the
multi-language name handling independently).
FeaCoordReceiverInternal::getCoordinates() β the real per-point decoder, disassembled and understood instruction-by-instruction
getCoordinates() (784 bytes) has almost no external calls (only one, to
thinout() β a real Douglas-Peucker-style line-simplification routine,
matching ThinoutAccuracy), meaning the actual coordinate math lives
directly in its own instructions β nothing hidden behind another
indirect call. The core loop, read field-by-field from the real machine
code:
for each 4-byte record in the chain:
dx = read_int16_BE(ptr[0:2]) # a big-endian signed 16-bit delta
dy = read_int16_BE(ptr[2:4])
if dx != 0 and dy != 0 and <a mode flag>:
break # conditional sentinel/terminator
accum_x += dx # this+0x18, a 16-bit accumulator
accum_y += dy # this+0x1a, a 16-bit accumulator
scale_x = layer_properties->field_0x50 # FeaLayerPropertiesInternal*
scale_y = layer_properties->field_0x54 # at this+0x2c
output.x = (int16)(accum_x * scale_x) # ONE LocalPoint per record
output.y = (int16)(accum_y * scale_y)
This is the same cumulative-delta-chain shape as MAP_COMPRESSED's own
already-cracked decode_vertex_chain() (research/ map_compressed_reader.py) β consistent with eeu.mod's own schema
declaring delta_long/delta_lat fields on this table too β but it is
a different, eeuz.fea-specific implementation: 16-bit (not 32-bit)
accumulators, and a final per-axis multiply by a scale factor pulled from
a separate FeaLayerPropertiesInternal object rather than a fixed
/100000 constant.
The 2 float constructor parameters are NOT an anchor β disassembly proves it
The natural hope, given init()'s real signature (init__ 24FeaCoordReceiverInternalPUcUlPciQ224FeaCoordReceiverInternal15ThinoutAccuracyP26FeaLayerPropertiesInternalff
β note the trailing ff, 2 floats) was that these 2 floats are a real-
world anchor coordinate (lon/lat) this entry's relative chain starts
from. Disassembled directly and refuted: init() (72 bytes) stores
the 2 floats verbatim into this+0x24/this+0x28 β fields
getCoordinates() never reads β and explicitly zeroes this+0x18/
this+0x1a (the x/y accumulators) and this+0x1c (the "first
iteration" flag). The accumulators always start at exactly (0, 0) β
proven by the init code itself, not inferred. Tracing one call site
(parseExtractedParcel) further found where those 2 floats actually come
from: a ratio of 4 different FeaLayerPropertiesInternal fields
(field_0x10/field_0x14 vs. field_0x20/field_0x24), computed via
the classic PowerPC int-to-double bit-trick then divided β the shape of
an accuracy/unit-conversion ratio (consistent with the real
s_pulAccuracyTable/s_pulAccuracyTableOrg/ThinoutAccuracy globals
found via relocations elsewhere in this same handler), not a geographic
coordinate.
What this means: eeuz.fea's own decode code, traced end to end from
db_fea_read_parcels_V005 through parseExtractedParcel into
FeaCoordReceiverInternal::getCoordinates(), never once supplies or
receives an absolute real-world position β only relative deltas scaled
by accuracy/unit factors. Combined with the type itself being named
LocalPoint (not GeoPoint/Coordinate) and this project's own
already-exhaustive, independently-refuted search for an absolute
coordinate anywhere in a decompressed entry's bytes (see "What's NOT
cracked" above), the most consistent reading is that an absolute anchor
is supplied externally, by whatever caller already knows where on the
map this entry belongs (plausibly the rendering/placement code, using a
tile or viewport position it already has from MAP_COMPRESSED) β not
something .fea's own bytes or DBAL.OUT's own code ever carry. Tracing
that external caller further would mean stepping outside DBAL.OUT into
the main FHDD6.FLI application image, which this project has already
established has its own, different disassembly wall (known function
names whose code addresses fall outside the disassemblable region,
confirmed across 3 independent firmware builds β see eeu.iof's own page
and research/swl_5238_reader.py) β so this may not be resolvable by
further firmware disassembly at all, not just "not yet resolved."
Not pursued further
parseExtractedParcel's own header-parsing logic (where exactly, within
one entry's bytes, the point/delta chain begins, and how feaPointCnt
gates its length) was not fully traced β the function is 2820 bytes and
only its first ~300 bytes (the accuracy-ratio computation above) were
disassembled in detail. A future session could trace the rest to at
least pin down the exact starting byte offset for a chain within a known
entry (e.g., IaΘi's), which would let the relative-delta decode above be
validated directly against real file bytes β not yet done this session.
Practical fallback (validated, useful on its own)
enumerate_entries() β brute-force but efficient back-to-back zlib
walking with automatic (now escalating-window) gap recovery β reliably
enumerates real entries across the whole file; scan_names() extracts the
multi-language name table from any given entry. Together these are, right
now, the only working way to enumerate and approximately geolocate
.fea content (via names), without a full coordinate decode.
Reader code
research/feature_reader.py (full validation numbers, every refuted
hypothesis, and remaining candidate leads in its module docstring) β
decode_directory_table(), verify_index_triple(),
find_index_record_for_offset(), enumerate_entries(), scan_names().
The DBAL.OUT disassembly above (real function/class names:
FeaCoordReceiverInternal::getCoordinates()/init(),
parseExtractedParcel, db_fea_read_parcels_V005, db_fea_init_V005)
was done ad hoc for this session β a short ELF32 big-endian section/
symbol/relocation-table parser plus capstone
(CS_ARCH_PPC/CS_MODE_BIG_ENDIAN/CS_MODE_32) against dbal/ V010_015/DBAL.OUT's raw .text bytes, same technique as eeu.iof's
own crack β not saved as a new research/
module (a one-off targeted read of specific functions, not a general-
purpose reader); reproducible directly from the function names/addresses
cited above.