#------------------------------------------------------------------------------
# $File: map,v 1.10 2023/02/03 20:41:57 christos Exp $
# map:  file(1) magic for Map data
#

# Garmin .FIT files https://pub.ks-and-ks.ne.jp/cycling/edge500_fit.shtml
8       string  .FIT            FIT Map data
>15     byte    0
>>35    belong  x               \b, unit id %d
>>39    lelong  x               \b, serial %u
# https://pub.ks-and-ks.ne.jp/cycling/edge500_fit.shtml
# 20 years after unix epoch
# TZ=GMT date -d '1989-12-31 0:00' +%s
>>43    leldate+631065600       x       \b, %s

>>47    leshort x               \b, manufacturer %d
>>47    leshort 1               \b (garmin)
>>49    leshort x               \b, product %d
>>53    byte    x               \b, type %d
>>53    byte    1               \b (Device)
>>53    byte    2               \b (Settings)
>>53    byte    3               \b (Sports/Cycling)
>>53    byte    4               \b (Activity)
>>53    byte    8               \b (Elevations)
>>53    byte    10              \b (Totals)

# Summary: Garmin map
# From: Joerg Jenderek
# URL: https://en.wikipedia.org/wiki/Garmin_.img
# Reference: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/IMG_File_Format
# sourceforge.net/projects/garmin-img/files/IMG%20File%20Format/1.0/imgformat-1.0.pdf
# GRR: similar to MBR boot sector handled by ./filesystems
0x1FE   leshort         =0xAA55
# look for valid map signature
>0x13   string          =IMG\0
>>0     use             garmin-map
0       name                            garmin-map
>0      ubyte           x               Garmin
!:mime  application/x-garmin-map
# If non-zero, every byte of the entire .img file is to be XORed with this value
>0      ubyte           !0              \b, %#x XORed
# goto block before FAT
>(0x40.b*512)   ubyte   x
# 1st fat name "DLLINFO TXT" only found for vpm
>>&512          string  =DLLINFO\ TXT   map (Voice Processing)
# there exist 2 other Garmin VPM formats; see ./audio
!:ext   vpm
# Deutsch__Yannick_D4481-00_0210.vpm
#>>>512 search/0x0116da60/s     RIFF    \b; with
# determine type voice type by ./riff
#>>>>&0 indirect        x       \b
>>&512          string  !DLLINFO\ TXT   map
!:ext   img
# 9 zeros
>1      ubelong         !0              \b, zeroes %#x
# Map's version major
>8      ubyte           x               v%u
# Map's version minor
>9      ubyte           x               \b.%.2u
# Map description[20], 0x20 padded
>0x49   string          x               %.20s
# Map name, continued (0x20 padded, \0 terminated)
>0x65   string          >\              \b%.31s
# Update year (+1900 for val >= 0x63, +2000 for val <= 0x62)
>0xB    ubyte           x               \b, updated
>>0xB   ubyte           >0x62
>>>0xB  ubyte-100       x               20%.2u
>>0xB   ubyte           <0x63
>>>0xB  ubyte           x               20%.2u
# Update month (0-11)
>0xA    ubyte           x               \b-%.2u
# All zeroes
>0xc    uleshort        !0              \b, zeroes %#x
# Mapsource flag, 1 - file created by Mapsource, 0 - Garmin map visible in Basecamp and Homeport
#>0xE   ubyte           !0              \b, Mapsource flag %#x
>0xE    ubyte           1               \b, Mapsource
# Checksum, sum of all bytes modulo 256 should be 0
#>0xF   ubyte           x               \b, Checksum %#x
# Signature: DSKIMG 0x00 or DSDIMG 0x00 for demo map
>0x10   string          !DSKIMG         \b, signature "%.7s"
>0x39   use             garmin-date
# Map file identifier like GARMIN\0
>0x41   string          !GARMIN         \b, id "%.7s"
# Block size exponent, E1; appears to always be 0x09; minimum block size 512 bytes
>0x61   ubyte           !0x09           \b, E1=%u
# Block size exponent, E2 ; file blocksize=2**(E1+E2)
>>0x62  ubyte           x               \b, E2=%u
>0x61   ubyte           =0x09           \b, blocksize
>>0x62  ubyte           0               512
>>0x62  ubyte           1               1024
>>0x62  ubyte           2               2048
>>0x62  ubyte           3               4096
>>0x62  ubyte           4               8192
>>0x62  ubyte           5               16384
>>0x62  default         x
>>>0x62 ubyte           x               E2=%u
# MBR signature
>0x1FE  leshort         !0xAA55         \b, invalid MBR
# 512 zeros
>0x200  uquad           !0              \b, zeroes %#llx
# First sub-file offset (absolute); sometimes NO/UNKNOWN sub file!
>0x40C  ulelong         >0              \b, at %#x
# sub-file Header length
#>>(0x40C.l)    uleshort        x       \b, header len %#x
>>(0x40C.l)     uleshort        x       %u bytes
# sub-file Type[10] like "GARMIN RGN" "GARMIN TRE", "GARMIN TYP", etc.
>>(0x40C.l+2)   ubyte   >0x1F
>>>(0x40C.l+2)  ubyte   <0xFF
>>>>(0x40C.l+2) string  x               "%.10s"
# 0x00 for most maps, 0x80 for locked maps (City Nav, City Select, etc.)
>>>>(0x40C.l+13)        ubyte   >0              \b, locked %#x
# Block sequence numbers like 0000 0100 0200 ... FFFF
# >0x420        ubequad         >0      \b, seq. %#16.16llx
# >>0x428       ubequad         >0      \b%16.16llx
# >>>0x430      ubequad >0      \b%16.16llx
# >>>>0x438     ubequad >0      \b%16.16llx
# >>>>>0x440    ubequad >0      \b%16.16llx
# >>>>>>0x448   ubequad >0      \b%16.16llx
# >>>>>>>0x450  ubequad >0      \b%16.16llx
# >>>>>>>>0x458 ubequad >0      \b%16.16llx
# >>>>>>>>>0x460        ubequad >0      \b%16.16llx
# >>>>>>>>>>0x468       ubequad >0      \b%16.16llx
# >>>>>>>>>>>0x470      ubequad >0      \b%16.16llx
# >>>>>>>>>>>>0x478     ubequad >0      \b%16.16llx
# >>>>>>>>>>>>>0x480    ubequad >0      \b%16.16llx
# >>>>>>>>>>>>>>0x488   ubequad >0      \b%16.16llx
# >>>>>>>>>>>>>>>0x490  ubequad >0      \b%16.16llx
# >>>>>>>>>>>>>>>>0x498 ubequad >0      \b%16.16llx
# >>>>>>>>>>>>>>>>>0x4A0        ubequad >0      \b%16.16llx
# >>>>>>>>>>>>>>>>>>0x4A8       ubequad >0      \b%16.16llx
# look for end of FAT
#>>0x420        search/512/s    \xff\xff        FAT END
# Physical block number of FAT header
#>0x40  ubyte           x               \b, FAT at phy. block %u
>0x40   ubyte           x
>>(0x40.b*512)  ubyte   x
# 1st FAT block
>>>&511         use     garmin-fat
# 2nd FAT block
>>>&1023        use     garmin-fat
# 3th FAT block
>>>&1535        use     garmin-fat
# 4th FAT block
>>>&2047        use     garmin-fat
# ... xth FAT block
#
# 314 zeros but not in vpm and also gmaptz.img
>0x84   uquad           !0              \b, at 0x84 %#llx
# display FileAllocationTable block entry in garmin map
0       name                            garmin-fat
>0      ubyte           x               \b;
# sub file part; 0x0003 seems to be garbage
>0x10   uleshort        !0              next %#4.4x
>0x10   uleshort        =0
# fat flag 0~dummy block 1~true sub file
>>0     ubyte           !1              flag %u
>>0     ubyte           =1
# sub-file name like MAKEGMAP 12345678
>>>0x1  string          x               %.8s
# sub-file typ like RGN TRE MDR LBL
>>>0x9  string          x               \b.%.3s
# size of sub file
>>>0xC  ulelong         x               \b, %u bytes
# 32-bit block sequence numbers
#>>>0x20        ubequad         x               \b, seq. %#16.16llx

#       display date stored inside Garmin maps like yyyy-mm-dd h:mm:ss
0       name                            garmin-date
# year like 2018
>0      uleshort        x               \b, created %u
# month (0-11)
>2      ubyte           x               \b-%.2u
# day (1-31)
>3      ubyte           x               \b-%.2u
# hour (0-23)
>4      ubyte           x               %u
# minute (0-59)
>5      ubyte           x               \b:%.2u
# second (0-59)
>6      ubyte           x               \b:%.2u

# Summary: Garmin Map subfiles
# From: Joerg Jenderek
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/IMG_File_Format
# Garmin Common Header
2       string  GARMIN\
# skip ASCII text by checking for low header length
>0      uleshort <0x1000        Garmin map,
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/GMP_Subfile_Format
>>9     string  GMP                             subtile
!:mime                  application/x-garmin-gpm
!:ext                   gmp
# copyright message
>>>(0.s)                string          x       %s
>>>0x0E                 use             garmin-date
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/MDR_Subfile_Format
# This contains the searchable address table used for finding routing destinations
>>9     string  MDR                             address table
!:mime                  application/x-garmin-mdr
!:ext                   mdr
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/NOD_Subfile_Format
# http://svn.parabola.me.uk/display/trunk/doc/nod.txt
# This contains the routing information
>>9     string  NOD                             routing
!:mime                  application/x-garmin-nod
!:ext                   nod
>>>0x0E                 use             garmin-date
#>>>0x15                        ulelong         x       \b, at %#x
#>>>0x19                        ulelong         x       %#x bytes NOD1
#>>>0x25                        ulelong         x       \b, at %#x
#>>>0x29                        ulelong         x       %#x bytes NOD2
#>>>0x31                        ulelong         x       \b, at %#x
#>>>0x35                        ulelong         x       %#x bytes NOD3
# URL: http://www.pinns.co.uk/osm/net.html
# routable highways (length, direction, allowed speed,house address information)
>>9     string  NET                             highways
!:mime                  application/x-garmin-net
!:ext                   net
#>>>0x15                        ulelong         x       \b, at %#x
#>>>0x19                        ulelong         x       %#x bytes NET1
#>>>0x22                        ulelong         >0
#>>>>0x1E               ulelong         x       \b, at %#x
#>>>>0x22               ulelong         x       %#x bytes NET2
#>>>0x2B                        ulelong         >0
#>>>>0x27               ulelong         x       \b, at %#x
#>>>>0x2B               ulelong         x       %#x bytes NET3
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/LBL_Subfile_Format
>>9     string  LBL                             labels
!:mime                  application/x-garmin-lbl
!:ext                   lbl
>>>(0.s)                string  x       %s
# Label coding type 6h 9h and ah
>>>0x1E                 ubyte           x       \b, coding type %#x
#>>>0x15                        ulelong         x       \b, at %#x
#>>>0x19                        ulelong         x       %#x bytes LBL1
#>>>0x1F                        ulelong         x       \b, at %#x
#>>>0x23                        ulelong         x       %#x bytes LBL2
#>>>0x2D                        ulelong         x       \b, at %#x
#>>>0x31                        ulelong         x       %#x bytes LBL3
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/SRT_Subfile_Format
# A lookup table of the chars in the map's codepage, and their collating sequence
>>9     string  SRT                             sort table
!:mime                  application/x-garmin-srt
!:ext                   srt
>>>0x0E                 use             garmin-date
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/TRE_Subfile_Format
>>9     string  TRE                             tree
!:mime                  application/x-garmin-tre
!:ext                   tre
# title like City Nav Europe NTU 2019.2 Basemap
# or OSM Street map
>>>(0.s)                string          x       %s
# 2nd title like Copyright 1995-2018 by GARMIN Corporation.
# or http://www.openstreetmap.org/
>>>>&1                  string          x       %s
>>>0x0E                 use             garmin-date
#>>>0x21                        ulelong         x       \b, at %#x
#>>>0x25                        ulelong         x       %#x bytes TRE1
#>>>0x29                        ulelong         x       \b, at %#x
#>>>0x2D                        ulelong         x       %#x bytes TRE2
#>>>0x31                        ulelong         x       \b, at %#x
#>>>0x35                        ulelong         x       %#x bytes TRE3
# Copyright record size
#>>>0x39                        uleshort        x       \b, copyright record size %u
# Map ID
>>>0x74                 ulelong         x       \b, ID %#x
# URL: https://www.gpspower.net/garmin-tutorials/353310-basecamp-installing-free-desktop-map.html
# For road traffic information service (RDS/TMS/TMC). Commonly seen in City Navigator maps
>>9     string  TRF                             traffic,
!:mime                  application/x-garmin-trf
!:ext                   trf
# city/region like Preitenegg
>>>(0.s+1)              string          x       1st %s
# highway part like L606/L148
>>>>&1                  string          x       %s
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/Format
# Reference: http://www.pinns.co.uk/osm/typformat.html
# customize the appearance of objects. For GPS and MapSource/Qlandkarte better looking maps
>>9     string  TYP                             types
!:mime                  application/x-garmin-typ
!:ext                   typ
>>>0x0E                 use             garmin-date
# character set 1252 65001~UTF8
>>>0x15                 uleshort        x       \b, code page %u
# POIs
#>>>0x17                        ulelong         x       \b, at %#x
#>>>0x1B                        ulelong         x       %#x bytes TYP1
# extra pois
#>>>0x5B                        ulelong         x       \b, at %#x
#>>>0x5F                        ulelong         x       %#x bytes TYP8
# URL: https://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/RGN_Subfile_Format
# http://www.pinns.co.uk/osm/RGN.html
# region data used by the Garmin software
>>9     string  RGN                             region
!:mime                  application/x-garmin-rgn
!:ext                   rgn
# POIs,Indexed POIs,Polylines or Polygons or first map level
#>>>0x15                        ulelong        x        \b, at %#x
#>>>0x19                        ulelong        x        %#x bytes RGN1
# polygons with extended types
#>>>0x21                        ulelong        >0
#>>>>0x1D               ulelong        x        \b, at %#x
#>>>>0x21               ulelong        x        %#x bytes RGN2
# polylines with extended types
#>>>0x3D                        ulelong        >0
#>>>>0x39               ulelong        x        \b, at %#x
#>>>>0x3D               ulelong        x        %#x bytes RGN3
# extended POIs
#>>>0x59                        ulelong        >0
#>>>>0x55               ulelong        x        \b, at %#x
#>>>>0x59               ulelong        x        %#x bytes RGN3
#>>9    default         x               unknown map type
# Header length; GMP:31h 35h 3Dh,MDR:11Eh 238h 2C4h 310h,NOD:3Fh 7Fh,NET:64h,
# LBL:2A9h,SRT:1Dh 25h 27h,TRE:CFh 135h,TRF:5Ah,TYP:5Bh 6Eh 7Ch AEh,RGN:7Dh
>>0     uleshort        x               \b, header length %#x

# URL:          https://www.memotech.franken.de/FileFormats/
# Reference:    https://www.memotech.franken.de/FileFormats/Garmin_RGN_Format.pdf
# From:         Joerg Jenderek
0       string          KpGr            Garmin update
# format version like: 0064h~1.0
>0x4    uleshort        !0x0064
>>4     uleshort/100    x               \b, version %u
>>4     uleshort%100    x               \b.%u
# 1st Garmin entry
>6      use     garmin-entry
# 2nd Garmin entry
>(0x6.l+10)     ubyte           x
>>&0            use             garmin-entry
# 3rd entry
>(0x6.l+10)     ubyte           x
>>&(&0.l+4)     ubyte           x
>>>&0           use             garmin-entry
# look again at version to use default clause
>0x4    uleshort        x
# test for region content by looking for
# Garmin *.srf by ./images with normal builder name "SQA" or longer "hales"
# 1 space after equal sign
>>0x3a  search/5/s      GARMIN\ BITMAP  \b=
!:mime  image/x-garmin-exe
!:ext   exe
>>>&0   indirect        x
# if not bitmap *.srf then region; 1 space after equal sign
>>0x3a  default         x               \b=
!:mime  application/x-garmin-rgn
!:ext   rgn
# recursiv embedded
>>>0x3a search/5/s      KpGrd
>>>>&0  indirect        x
# look for ZIP or JAR archive by ./archive and ./zip
>>>0x3a search/5/s      PK\003\004
>>>>&0  indirect        x
# TODO: other garmin RGN record content like foo
#>>0x3a search/5/s      bar             BAR
#               display information of Garmin RGN record
0       name    garmin-entry
# record length: 2 for Data, for Application often 1Bh sometimes 1Dh, "big" for Region
#>0     ulelong         x               \b, length %#x
# data record (ID='D') with version content like 0064h~1.0
>4      ubyte           =0x44
>>5     uleshort        !0x0064         \b; Data
>>>5    uleshort/100    x               \b, version %u
>>>5    uleshort%100    x               \b.%u
# Application Record (ID='A')
>4      ubyte           =0x41           \b; App
# version content like 00c8h~2.0
>>5     uleshort        !0x00C8
>>>5    uleshort/100    x               \b, version %u
>>>5    uleshort%100    x               \b.%u
# builder name like: SQA sqa build hales
>>7     string          x               \b, build by %s
# build date like: Oct 25 1999, Oct 1 2008, Feb 23 2009, Dec 15 2009
>>>&1   string          x               %s
# build time like: 11:26:12, 11:45:54, 14:16:13, 18:23:01
>>>>&1  string          x               %s
# region record (ID='R')
>4      ubyte           =0x52           \b; Region
# region ID:14~fw_all.bin: 78~ZIP, RGN or SRF bitmap; 148~ZIP or JAR; 249~display firmware; 251~WiFi or GCD firmware; 255~ZIP
>>5     uleshort        x               ID=%u
# delay in ms: like 0, 500
>>7     ulelong         !0              \b, %u ms
# region size (is record length - 10)
#>>11   ulelong         x               \b, length %#x
# region content like:
# "KpGr"~recursiv embedded,"GARMIN BITMAP"~Garmin Bitmap *.srf, "PK"~ZIP archive
#>>15   string          x               \b, content "%s"
>>15    ubequad         x               \b, content %#llx...
# This does NOT WORK!
#>>15   indirect        x               \b; contains
>4      default         x               \b; other
# garmin Record ID Identifies the record content like: D A R
>>4     ubyte           x               ID '%c'

# TOM TOM GPS watches ttbin files:
# https://github.com/ryanbinns/ttwatch/tree/master/ttbin
# From: Daniel Lenski
0       byte    0x20
>1      leshort 0x0007
>>0x76  byte    0x20
>>>0x77 leshort 0x0075          TomTom activity file, v7
>>>>8   leldate x               (%s,
>>>>3   byte    x               device firmware %d.
>>>>4   byte    x               \b%d.
>>>>5   byte    x               \b%d,
>>>>6   leshort x               product ID %04d)

# Garmin firmware:
# https://www.memotech.franken.de/FileFormats/Garmin_GCD_Format.pdf
# https://www.gpsrchive.com/GPSMAP/GPSMAP%2066sr/Firmware.html
0       string          GARMIN
>6      uleshort        100     GARMIN firmware (version 1.0)