#
# Keyman is copyright (C) SIL International. MIT License.
#
# basic.txt describes the expected output of running kmc against basic.xml. It is used in
# the end-to-end test test-compiler-e2e.ts.
#
# Any changes to the compiler or basic.xml will likely result in changes to the compiled file.
# While structural differences should be updated manually in this file to ensure that we are
# getting the expected result for the e2e test, the checksum can be safely retrieved from the
# updated compilation result. The following may be helpful for working with this file when
# updating the binary format:
#
#    cd developer/src/kmc
#    ./build.sh configure build # if needed
#    ./build.sh build-fixtures
#
#  This will compile both the .xml and the .txt to build/test/fixtures and also emit the
#  checksum for basic-xml.kmx so you can patch that into this file.
#
# For the format of this file, see “hextobin.ts”
#
# P.S. surprisingly, the Dart language highlighter in VSCode does a helpful job on this file.

block(kmxheader)  #  struct COMP_KEYBOARD {
  4b 58 54 53      #    KMX_DWORD dwIdentifier;   // 0000 Keyman compiled keyboard id

  00 11 00 00      #    KMX_DWORD dwFileVersion;  // 0004 Version of the file - Keyman 4.0 is 0x0400

  00 00 00 00      #    KMX_DWORD dwCheckSum;     // 0008 deprecated in 16.0, always 0
  00 00 00 00      #    KMX_DWORD KeyboardID;     // 000C as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts
  01 00 00 00      #    KMX_DWORD IsRegistered;   // 0010
  00 00 00 00      #    KMX_DWORD version;        // 0014 keyboard version

  sizeof(stores,12) #    KMX_DWORD cxStoreArray;   // 0018 in array entries
  00 00 00 00       #    KMX_DWORD cxGroupArray;   // 001C in array entries

  offset(stores)   #    KMX_DWORD dpStoreArray;   // 0020 [LPSTORE] address of first item in store array
  00 00 00 00      #    KMX_DWORD dpGroupArray;   // 0024 [LPGROUP] address of first item in group array

  ff ff ff ff      #    KMX_DWORD StartGroup[2];  // 0028 index of starting groups [2 of them]
  ff ff ff ff      #

  20 00 00 00      #    KMX_DWORD dwFlags;        // 0030 Flags for the keyboard file

  00 00 00 00      #    KMX_DWORD dwHotKey;       // 0034 standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)

  00 00 00 00      #    KMX_DWORD dpBitmapOffset; // 0038 offset of the bitmaps in the file
  00 00 00 00      #    KMX_DWORD dwBitmapSize;   // 003C size in bytes of the bitmaps
                   #  };

block(kmxplusinfo)                  #  struct COMP_KEYBOARD_KMXPLUSINFO {
  offset(sect)                      #    KMX_DWORD dpKMXPlus;      // 0040 offset of KMXPlus data from BOF, <sect> header is first
  diff(sect,eof)                    #    KMX_DWORD dwKMXPlusSize;  // 0044 size in bytes of entire KMXPlus data
                                    #  };

block(stores)                          #  struct COMP_STORE {
  07 00 00 00                          #  KMX_DWORD dwSystemID; - TSS_NAME
  offset(store_name_name)              #  KMX_DWORD dpName;
  offset(store_name_string)            #  KMX_DWORD dpString;
                                       #  };
  # excluding this so we don’t have compiled version changes
  # 14 00 00 00                          #  KMX_DWORD dwSystemID; - TSS_COMPILEDVERSION
  # offset(store_compiledversion_name)   #  KMX_DWORD dpName;
  # offset(store_compiledversion_string) #  KMX_DWORD dpString;
                                       #  };
  24 00 00 00                          #  KMX_DWORD dwSystemID; - TSS_KEYBOARDVERSION
  offset(store_keyboardversion_name)   #  KMX_DWORD dpName;
  offset(store_keyboardversion_string) #  KMX_DWORD dpString;
                                       #  };
  26 00 00 00                          #  KMX_DWORD dwSystemID; - TSS_TARGETS
  offset(store_targets_name)           #  KMX_DWORD dpName;
  offset(store_targets_string)         #  KMX_DWORD dpString;
                                       #  };

  18 00 00 00                           # TSS_VISUALKEYBOARD
  00 00 00 00                           #  KMX_DWORD dpName;
  offset(store_vk_path_string)               #  KMX_DWORD dpString;

block(store_name_name)
  26 00 4e 00 41 00 4d 00 45 00 00 00  # '&NAME'
block(store_name_string)
  54 00 65 00 73 00 74 00 4b 00 62 00 64 00 00 00 # 'TestKbd'

block(store_keyboardversion_name)
  26 00 4b 00 45 00 59 00 42 00 4f 00 41 00 52 00
  44 00 56 00 45 00 52 00 53 00 49 00 4f 00 4e 00
  00 00                                # '&KEYBOARDVERSION'
block(store_keyboardversion_string)
  31 00 2e 00 30 00 2e 00 30 00 00 00  # '1.0.0'

block(store_targets_name)
  26 00 54 00 41 00 52 00 47 00 45 00 54 00 53 00 00 00 # '&TARGETS'
block(store_targets_string)
  64 00 65 00 73 00 6b 00 74 00 6f 00 70 00 00 00 # 'desktop'
block(store_vk_path_string)
  62 00 61 00 73 00 69 00 63 00 2d 00 78 00 6d 00 6c 00 2e 00 6b 00 76 00 6b 00 00 00 # 'basic-xml.kvk'

block(sect)                         #  struct COMP_KMXPLUS_SECT {
  73 65 63 74                       #    KMX_DWORD header.ident;   // 0000 Section name
  diff(sect,endsect)                #    KMX_DWORD header.size;    // 0004 Section length
  diff(sect,eof)                    #    KMX_DWORD total;          // 0008 KMXPlus entire length
  sizeof(sectitems,8)               #    KMX_DWORD count;          // 000C number of section headers
                                    #  };
  # Next sections are sect entries
  #    KMX_DWORD sect;           // 0010+ Section identity
  #    KMX_DWORD offset;         // 0014+ Section offset relative to dpKMXPlus of section

block(sectitems)
  62 6b 73 70
  diff(sect,bksp)

  64 69 73 70
  diff(sect,disp)

  65 6c 65 6d
  diff(sect,elem)

  6b 65 79 73
  diff(sect,keys)

  6c 61 79 72
  diff(sect,layr)

  6c 69 73 74
  diff(sect,list)

  6c 6f 63 61
  diff(sect,loca)

  6d 65 74 61
  diff(sect,meta)

  73 74 72 73
  diff(sect,strs)

  74 72 61 6e
  diff(sect,tran)

  75 73 65 74
  diff(sect,uset)

  76 61 72 73
  diff(sect,vars)

block(endsect)

# ----------------------------------------------------------------------------------------------------
# bksp
# ----------------------------------------------------------------------------------------------------

block(bksp)
  # TODO-LDML: see 'tran' for a more programmatic way to calculate the fields
  62 6b 73 70
  sizeof(bksp)
  01 00 00 00                       #   KMX_DWORD groupCount
  01 00 00 00                       #   KMX_DWORD transformCount
  00 00 00 00                       #   KMX_DWORD reorderCount

  # group 0
  00 00 00 00                       #   KMX_DWORD type = transform
  01 00 00 00                       #   KMX_DWORD count = 1
  00 00 00 00                       #   KMX_DWORD index = 0

  # transforms 0
  index(strNull,strElemTranFrom1b,2) #   KMX_DWORD str from  ^e ## << ??
  index(strNull,strNull,2)          #   KMX_DWORD str to 0
  index(strNull,strNull,2)          #   KMX_DWORD str mapFrom 0
  index(strNull,strNull,2)          #   KMX_DWORD str mapTo 0


# ----------------------------------------------------------------------------------------------------
# disp
# ----------------------------------------------------------------------------------------------------

block(disp)                         # struct COMP_KMXPLUS_DISP {
  64 69 73 70                       #   KMX_DWORD header.ident;   // 0000 Section name - disp
  sizeof(disp)                      #   KMX_DWORD header.size;    // 0004 Section length
  02 00 00 00                       #   KMX_DWORD count;          // 0008 number of entries
  index(strNull,strElemBkspFrom2,2) #   KMX_DWORD baseCharacter   // 000C baseCharacter = 'e'
                                    # };

                                    # entry 0
  index(strNull,strA,2)             #   KMX_DWORD to       // 000C baseCharacter = 'a'
  index(strNull,strNull,2)          #   KMX_DWORD id 0
  index(strNull,strElemTranFrom1,2) #   KMX_DWORD display   // 000C baseCharacter = '^'

                                    # entry 1
  index(strNull,strNull,2)           #   KMX_DWORD to       // 000C baseCharacter = 'a'
  index(strNull,strElemBkspFrom2,2) #   KMX_DWORD id  'e'
  index(strNull,strElemTranFrom1b,2) #   KMX_DWORD display   '^e'



# ----------------------------------------------------------------------------------------------------
# elem
# ----------------------------------------------------------------------------------------------------

block(elem)                         # struct COMP_KMXPLUS_ELEM {
  65 6c 65 6d                       #   KMX_DWORD header.ident;   // 0000 Section name - elem
  diff(elem,endelem)                #   KMX_DWORD header.size;    // 0004 Section length
  index(elemNull,endelem)           #   KMX_DWORD count;          // 0008 number of entries
                                    # };

#strings
  #elem #0 null element
  00 00 00 00                       #    KMX_DWORD offset;                 // 0010+ offset from this blob
  sizeof(elemNull,8)                #    KMX_DWORD length;                 // 0014+ str length (ELEMENT units)

  #elem #1 count=03
  #elem #2 count=03
  #elem #3 count=01


  diff(elem,elemSet)                #    KMX_DWORD offset;                 // 0010+ offset from this blob
  sizeof(elemSet,8)                 #    KMX_DWORD length;                 // 0014+ str length (ELEMENT units)

  diff(elem,elemOrdrFrom)           #    KMX_DWORD offset;                 // 0010+ offset from this blob
  sizeof(elemOrdrFrom,8)            #    KMX_DWORD length;                 // 0014+ str length (ELEMENT units)

  diff(elem,elemOrdrBefore)         #    KMX_DWORD offset;                 // 0010+ offset from this blob
  sizeof(elemOrdrBefore,8)          #    KMX_DWORD length;                 // 0014+ str length (ELEMENT units)

# now the elements
block(elemNull)

block(elemSet)
  61 00 00 00              #    KMX_DWORD element; 'a'
  00 00 00 00              #    KMX_DWORD flags;
  62 00 00 00              #    KMX_DWORD element; 'b'
  00 00 00 00              #    KMX_DWORD flags;
  63 00 00 00              #    KMX_DWORD element; 'c'
  00 00 00 00              #    KMX_DWORD flags;

block(elemOrdrFrom)
  # from="\u{1A60}[\u1A75-\u1A79]\u{1A45}" order="10 55 10"
  60 1a 00 00                        #    KMX_DWORD element;   '᩠'             // str: output string or UTF-32LE codepoint
  00 00 0A 00                        #    KMX_DWORD flags;                  // flag and order values - cp
  00 00 00 00  # TODO-LDML: uset #0  #    KMX_DWORD element;   [uset]       // str: output string or UTF-32LE codepoint
  02 00 37 00                        #    KMX_DWORD flags;                  // flag and order values - unicodeset
  45 1A 00 00                        #    KMX_DWORD element;   'ᩅ'          // str: output string or UTF-32LE codepoint
  00 00 0A 00                        #    KMX_DWORD flags;                  // flag and order values - unicodeset

block(elemOrdrBefore)
  # before="\u{1A6B}"
  6b 1a 00 00                        #    KMX_DWORD element;   'ᩫ'              // str: output string or UTF-32LE codepoint
  00 00 00 00                        #    KMX_DWORD flags;                  // flag and order values - unicodeset

block(endelem)

# ----------------------------------------------------------------------------------------------------
# keys
# ----------------------------------------------------------------------------------------------------

block(keys)                         # struct COMP_KMXPLUS_KEYS {
  6b 65 79 73                       #   KMX_DWORD header.ident;   // 0000 Section name - keys
  sizeof(keys)                      #   KMX_DWORD header.size;    // 0004 Section length
  05 00 00 00                       #   KMX_DWORD keyCount
  01 00 00 00                       #   KMX_DWORD flicksCount
  00 00 00 00                       #   KMX_DWORD flickCount
  30 00 00 00                       #   KMX_DWORD kmapCount;          // 0008 number of kmap - #48, one per key
  # keys
  # (#0000) a
  61 00 00 00                       #   'a'
  00 00 00 00                       #   KMX_DWORD flags = 0
  index(strNull,strA,2)             #   KMXPLUS_STR 'a' (key id)
  00 00 00 00                       #   KMXPLUS_STR switch
  0A 00 00 00                       #   KMX_DWORD width*10
  00 00 00 00                       # TODO: index(listNull,listNull,4)        #   LIST longPress
  00 00 00 00                       #   STR longPressDefault
  00 00 00 00                       # TODO: index(listNull,listNull,4)        #   LIST multiTap
  00 00 00 00                       #  flicks
  # (#0001) e
  65 00 00 00                       #   'e'
  00 00 00 00                       #   KMX_DWORD flags = 0
  index(strNull,strElemBkspFrom2,2)  #   KMXPLUS_STR 'e' (key id)
  00 00 00 00                       #   KMXPLUS_STR switch
  0A 00 00 00                       #   KMX_DWORD width*10
  00 00 00 00                       # TODO: index(listNull,listNull,4)        #   LIST longPress
  00 00 00 00                       #   STR longPressDefault
  00 00 00 00                       # TODO: index(listNull,listNull,4)        #   LIST multiTap
  00 00 00 00                       #  flicks
  # (#0002) gap (reserved)
  00 00 00 00                       #   nothing
  03 00 00 00                       #   KMX_DWORD flags = extend|gap
  index(strNull,strGapReserved,2)  #   KMXPLUS_STR 'gap (reserved)' (key id)
  00 00 00 00                       #   KMXPLUS_STR switch
  0A 00 00 00                       #   KMX_DWORD width*10  (full width)
  00 00 00 00                       # TODO: index(listNull,listNull,4)        #   LIST longPress
  00 00 00 00                       #   STR longPressDefault
  00 00 00 00                       # TODO: index(listNull,listNull,4)        #   LIST multiTap
  00 00 00 00                       #  flicks
  # (#0003) hmaqtugha
  27 01 00 00                       #   UTF-32    'U+0127'
  00 00 00 00                       #   KMX_DWORD (flags: none)
  index(strNull,strHmaqtugha,2)     #   KMXPLUS_STR 'hmaqtugha'
  00 00 00 00                       #   KMXPLUS_STR switch
  0A 00 00 00                       #   KMX_DWORD width*10
  02 00 00 00 # TODO: index(listNull,indexAe,4)         #   LIST longPress 'a e'
  00 00 00 00                       #   STR longPressDefault
  00 00 00 00 # TODO: index(listNull,listNull,4)        #   LIST multiTap
  00 00 00 00                       #   flicks 0
  # (#0004) that
  index(strNull,strKeys,2)          #   KMXPLUS_STR '...'
  01 00 00 00                       #   KMX_DWORD flags = extend
  index(strNull,strThat,2)          #   KMXPLUS_STR 'that'
  00 00 00 00                       #   KMXPLUS_STR switch
  0A 00 00 00                       #   KMX_DWORD width*10
  00 00 00 00 # TODO: index(listNull,listNull,4)        #   LIST longPress
  00 00 00 00                       #   STR longPressDefault
  00 00 00 00 # TODO: index(listNull,listNull,4)        #   LIST multiTap
  00 00 00 00                       #   flicks 0
  # flicks
  #  flicks 0 - null
  00 00 00 00                       #   KMX_DWORD count
  00 00 00 00                       #   KMX_DWORD flick
  00 00 00 00                       #   KMX_STR id
  # flick
  # Right now there aren’t any flick elements.
  #00 00 00 00                       #   LIST directions
  #00 00 00 01                       #   flags
  #00 00 00 00                       #   str: to

  # kmapdata:
  # note that 'a' and 'e' are omitted, as they aren't on the layers (just from gestures)

  # moving these to 1-liners so they can be sorted! the structure is as follows:
  ## 31 00 00 00                        #  KMX_DWORD vkey
  ## 00 00 00 00                        #  KMX_DWORD modifiers (none)
  ## 04 00 00 00                        #  KMX_DWORD key index (that)

# following lines generated with this snippet:
#
#      /** from scanCodes-implied.xml */
#      const scans = ("29 02 03 04 05 06 07 08 09 0A 0B 0C 0D" + " 10 11 12 13 14 15 16 17 18 19 1A 1B 2B" + " 1E 1F 20 21 22 23 24 25 26 27 28" + " 2C 2D 2E 2F 30 31 32 33 34 35").split(/ /);
#
#      for (let s of scans) {
#        const n = Number.parseInt(s, 16);
#        const v = CLDRScanToUSVirtualKeyCodes[n]; // virtual-key-constants.ts
#        if (!v) {
#          console.error(`! ${s}`);
#        } else {
#          console.log(`  ${Number(v).toString(16)} 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)`);
#        }
#      }

#   - vkey -   - modifier -   - key id  -
  20 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  30 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  31 00 00 00   00 00 00 00   04 00 00 00 # "that"
  32 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  33 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  34 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  35 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  36 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  37 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  38 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  39 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  41 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  42 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  43 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  44 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  45 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  46 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  47 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  48 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  49 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  4a 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  4b 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  4c 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  4d 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  4e 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  4f 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  50 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  51 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  52 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  53 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  54 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  55 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  56 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  57 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  58 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  59 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  5a 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  ba 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  bb 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  bc 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  bd 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  be 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  bf 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  c0 00 00 00   00 00 00 00   03 00 00 00 # "hmaqtugha"
  db 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  dc 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  dd 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)
  de 00 00 00   00 00 00 00   02 00 00 00 # gap (reserved)

# ----------------------------------------------------------------------------------------------------
# layr
# ----------------------------------------------------------------------------------------------------

block(layr)                         # struct COMP_KMXPLUS_LAYR {
  6c 61 79 72                       #   KMX_DWORD header.ident;   // 0000 Section name - layr
  sizeof(layr)                      #   KMX_DWORD header.size;    // 0004 Section length
  01 00 00 00                       #   KMX_DWORD listCount
  01 00 00 00                       #   KMX_DWORD layerCount
  01 00 00 00                       #   KMX_DWORD rowCount
  02 00 00 00                       #   KMX_DWORD keyCount
  # list 0
  index(strNull,strUs,2)            #   KMXPLUS_STR hardware = 'us'
  00 00 00 00                       #   KMX_DWORD layer;
  01 00 00 00 # count
  7B 00 00 00                       #   KMX_DWORD minDeviceWidth; // 123
  # layers 0
  00 00 00 00                       #   KMXPLUS_STR id;
  00 00 00 00                       #   KMX_DWORD mod
  00 00 00 00                       #   KMX_DWORD row index
  01 00 00 00                       #   KMX_DWORD  count
  # rows 0
  00 00 00 00                       #   KMX_DWORD key index
  02 00 00 00                       #   KMX_DWORD count
  # keys
  index(strNull,strHmaqtugha,2)     #   KMXPLUS_STR locale;       // 'hmaqtugha'
  index(strNull,strThat,2)          #   KMXPLUS_STR locale;       // 'that'

# ----------------------------------------------------------------------------------------------------
# list
# ----------------------------------------------------------------------------------------------------

# TODO-LDML: lots of comment-out ahead. Need to revisit.

block(list)                         # struct COMP_KMXPLUS_LAYR_LIST {
  6c 69 73 74                       #   KMX_DWORD header.ident;   // 0000 Section name - list
  diff(list,endList)                #   KMX_DWORD header.size;    // 0004 Section length
  03 00 00 00                       #   KMX_DWORD listCount (should be 2)
  03 00 00 00                       #   KMX_DWORD indexCount (should be 2)
  # list #0 the null list
  block(listNull)
  00 00 00 00 #index(indexNull,indexNull,2)      #   KMX_DWORD list index (0)
  00 00 00 00                       #   KMX_DWORD lists[0].count
  block(listA)
  00 00 00 00 # first index
  01 00 00 00 #count
  block(listAe)
  01 00 00 00 # index(indexAe,indexNull,2)        #   KMX_DWORD list index (also 0)
  02 00 00 00                       #   KMX_DWORD count
  block(endLists)
  # indices
  #block(indexNull)
  # No null index
  # index(strNull,strNull,2)         #   KMXPLUS_STR string index
  block(indexA)
  index(strNull,strA,2) # a
  block(indexAe)
  index(strNull,strA,2) #   KMXPLUS_STR a
  index(strNull,strElemBkspFrom2,2) #   KMXPLUS_STR e
  block(endIndices)
  block(endList)

# ----------------------------------------------------------------------------------------------------
# loca
# ----------------------------------------------------------------------------------------------------

block(loca)                         # struct COMP_KMXPLUS_LOCA {
  6c 6f 63 61                       #   KMX_DWORD header.ident;   // 0000 Section name - loca
  sizeof(loca)                      #   KMX_DWORD header.size;    // 0004 Section length
  01 00 00 00                       #   KMX_DWORD count;          // 0008 number of locales
  index(strNull,strLocale,2)        #   KMXPLUS_STR locale;       // 000C+ locale string entry = 'mt'
                                    # };
# ----------------------------------------------------------------------------------------------------
# meta
# ----------------------------------------------------------------------------------------------------

block(meta)                         # struct COMP_KMXPLUS_META {
  6d 65 74 61                       #   KMX_DWORD header.ident;   // 0000 Section name - meta
  sizeof(meta)                      #   KMX_DWORD header.size;    // 0004 Section length
  index(strNull,strAuthor,2)        #   KMXPLUS_STR author;
  index(strNull,strConformsTo,2)    #   KMXPLUS_STR conform;
  index(strNull,strLayout,2)        #   KMXPLUS_STR layout;
  index(strNull,strName,2)          #   KMXPLUS_STR name;
  index(strNull,strIndicator,2)     #   KMXPLUS_STR indicator;
  index(strNull,strVersion,2)       #   KMXPLUS_STR version;
  00 00 00 00                       #   KMX_DWORD settings;
                                    # };

# ----------------------------------------------------------------------------------------------------
# strs
# ----------------------------------------------------------------------------------------------------

block(strs)                         #  struct COMP_KMXPLUS_STRS {
  73 74 72 73                       #    KMX_DWORD header.ident;   // 0000 Section name - strs
  diff(strs,endstrs)                #    KMX_DWORD header.size;    // 0004 Section length
  index(strNull,endstrs,2)          #    KMX_DWORD count;          // 0008 count of str entries
                                    # };

  # Next sections are string entries
  #    KMX_DWORD offset;         // 0010+ offset from this blob
  #    KMX_DWORD length;         // 0014+ str length (UTF-16LE units)

  diff(strs,strNull)       sizeof(strNull,2)
  diff(strs,strVersion)    sizeof(strVersion,2)
  diff(strs,strConformsTo) sizeof(strConformsTo,2)
  diff(strs,strName)       sizeof(strName,2)
  diff(strs,strFromSet)     sizeof(strFromSet,2)
  diff(strs,strUSet)       sizeof(strUSet,2)
  diff(strs,strAmarker)     sizeof(strAmarker,2)
  diff(strs,strSentinel0001r)  sizeof(strSentinel0001r,2)
  diff(strs,strElemTranFrom1) sizeof(strElemTranFrom1,2)
  diff(strs,strElemTranFrom1a) sizeof(strElemTranFrom1a,2)
  diff(strs,strElemTranFrom1b) sizeof(strElemTranFrom1b,2)
  diff(strs,strA)   sizeof(strA,2)
  diff(strs,strSet)   sizeof(strSet,2)
  diff(strs,strSet2)   sizeof(strSet2,2)
  diff(strs,strTranTo)          sizeof(strTranTo,2)
  diff(strs,strElemBkspFrom2) sizeof(strElemBkspFrom2,2)
  diff(strs,strGapReserved) sizeof(strGapReserved,2)
  diff(strs,strHmaqtugha) sizeof(strHmaqtugha,2)
  diff(strs,strLocale)     sizeof(strLocale,2)
  diff(strs,strLayout)     sizeof(strLayout,2)
  diff(strs,strAuthor)     sizeof(strAuthor,2)
  diff(strs,strThat)   sizeof(strThat,2)
  diff(strs,strUs)    sizeof(strUs,2)
  diff(strs,strVse)   sizeof(strVse,2)
  diff(strs,strVst)   sizeof(strVst,2)
  diff(strs,strVus)   sizeof(strVus,2)
  diff(strs,strKeys)       sizeof(strKeys,2)
  diff(strs,strIndicator)  sizeof(strIndicator,2)
  diff(strs,strSentinel0001)  sizeof(strSentinel0001,2)

  # String table -- block(x) is used to store the null u16char at end of each string
  #                 without interfering with sizeof() calculation above

#str #00
  block(strNull)             block(x) 00 00                                             # the zero-length string
  block(strVersion)          31 00 2e 00 30 00 2e 00 30 00   block(x) 00 00             # '1.0.0'
  block(strConformsTo)       34 00 35 00 block(x) 00 00                         # '45'
  block(strName)             54 00 65 00 73 00 74 00 4b 00 62 00 64 00   block(x) 00 00 # 'TestKbd'
  block(strFromSet)          5B 00 5C 00 75 00 31 00 41 00 37 00 35 00 2D 00 5C 00 75 00 31 00 41 00 37 00 39 00 5D 00 block(x) 00 00 # [\u1a75-\u1a79]
  block(strUSet)             5b 00 61 00 62 00 63 00 5d 00 block(x) 00 00               # '[abc]'
  block(strAmarker)          5C 00 6D 00 7B 00 61 00 7D 00 block(x) 00 00               # '\m{a}'
  block(strSentinel0001r)    5c 00 75 00 66 00 66 00 66 00 66 00 5c 00 75 00 30 00 30 00 30 00 38 00 5C 00 75 00 30 00 30 00 30 00 31 00 block(x) 00 00     # UC_SENTINEL CODE_DEADKEY \u0001 (regex form)
  block(strElemTranFrom1)    5E 00 block(x) 00 00                                       # '^'
  block(strElemTranFrom1a)   5E 00 61 00 block(x) 00 00                                       # '^a'
  block(strElemTranFrom1b)   5E 00 65 00 block(x) 00 00                                       # '^e'
  block(strA)    61 00 block(x) 00 00                                       # 'a'
  block(strSet)              61 00 20 00 62 00 20 00 63 00 block(x) 00 00               # 'a b c'
#str #0A
  block(strSet2)             61 00 62 00 63 00 block(x) 00 00                           # 'abc'
  block(strTranTo)           61 00 02 03 block(x) 00 00                          # 'â' (U+0061 U+0302)
  block(strElemBkspFrom2)    65 00 block(x) 00 00                                       # 'e'
  block(strGapReserved)         67 00 61 00 70 00 20 00 28 00 72 00 65 00 73 00 65 00 72 00 76 00 65 00 64 00 29 00 block(x) 00 00 # 'gap (reserved)'
  block(strHmaqtugha)        68 00 6d 00 61 00 71 00 74 00 75 00 67 00 68 00 61 00 block(x) 00 00   # 'hmaqtugha'
#str #10
  block(strLocale)           6d 00 74 00   block(x) 00 00                               # 'mt'
  block(strLayout)           71 00 77 00 65 00 72 00 74 00 79 00   block(x) 00 00       # 'qwerty'
  block(strAuthor)           73 00 72 00 6c 00 32 00 39 00 35 00   block(x) 00 00       # 'srl295'
  block(strThat)             74 00 68 00 61 00 74 00 block(x) 00 00                     # 'that'
  block(strUs)               75 00 73 00 block(x) 00 00                           # 'us' (layout)
  block(strVse)              76 00 73 00 65 00 block(x) 00 00                     # 'vse'
  block(strVst)              76 00 73 00 74 00 block(x) 00 00                     # 'vst'
  block(strVus)              76 00 75 00 73 00 block(x) 00 00                     # 'vus'
#str #1a
  block(strKeys)             90 17 b6 17 block(x) 00 00                               # 'ថា'
  # <reorder before="ᩫ" from="᩠᩵ᩅ" order="10 55 10" />
  block(strIndicator)        3d d8 40 de block(x) 00 00                               # '🙀'
  block(strSentinel0001)    FF FF 08 00 01 00 block(x) 00 00                         # UC_SENTINEL CODE_DEADKEY U+0001


block(endstrs)                      # end of strs block

# ----------------------------------------------------------------------------------------------------
# tran
# ----------------------------------------------------------------------------------------------------

block(tran)                         # struct COMP_KMXPLUS_TRAN {
  74 72 61 6e                       #   KMX_DWORD header.ident;   // 0000 Section name - tran
  diff(tran,tranEnd)                #   KMX_DWORD header.size;    // 0004 Section length
  diff(tranGroupStart,tranTransformStart,12) #   KMX_DWORD groupCount;
  diff(tranTransformStart,tranReorderStart,16) #   KMX_DWORD transformCount;
  diff(tranReorderStart,tranEnd,8) #   KMX_DWORD reorderCount;

  block(tranGroupStart)             # COMP_KMXPLUS_TRAN_GROUP
    # group 0
    00 00 00 00                       # KMX_DWORD type = transform
    02 00 00 00                       # KMX_DWORD count
    diff(tranTransformStart,tranTransform0,16) # KMX_DWORD index

    # group 1
    00 00 00 00                       # KMX_DWORD type = transform
    01 00 00 00                       # KMX_DWORD count
    diff(tranTransformStart,tranTransform2,16) # KMX_DWORD index

    # group 2
    01 00 00 00                       # KMX_DWORD type = reorder
    01 00 00 00                       # KMX_DWORD count
    diff(tranReorderStart,tranReorder0,8) # KMX_DWORD index

  # transforms
  block(tranTransformStart)         # COMP_KMXPLUS_TRAN_TRANSFORM
    block(tranTransform0)
    index(strNull,strElemTranFrom1a,2)  #    KMXPLUS_STR from;
    index(strNull,strTranTo,2)        #    KMXPLUS_STR to;
    index(strNull,strNull,2)          # mapFrom
    index(strNull,strNull,2)          # mapTo

  block(tranTransform1)
    index(strNull,strA,2)  #    KMXPLUS_STR from; 'a'
    index(strNull,strSentinel0001,2)        #    KMXPLUS_STR to; \m{a} (plain form)
    index(strNull,strNull,2)          # mapFrom
    index(strNull,strNull,2)          # mapTo

  block(tranTransform2)  # Next group
    index(strNull,strSentinel0001r,2)  #    KMXPLUS_STR from; (\m{a}) (regex form)
    index(strNull,strNull,2)        #    KMXPLUS_STR to; (none)
    index(strNull,strNull,2)          # mapFrom
    index(strNull,strNull,2)          # mapTo

  # reorders
  block(tranReorderStart)           # COMP_KMXPLUS_TRAN_REORDER
    block(tranReorder0)
    index(elemNull,elemOrdrFrom)      #    KMXPLUS_ELEM elements;
    index(elemNull,elemOrdrBefore)    #    KMXPLUS_ELEM before;

block(tranEnd)

block(uset)
  75 73 65 74                       #   KMX_DWORD header.ident;   // 0000 Section name - uset
  diff(uset,usetEnd)                #   KMX_DWORD header.size;    // 0004 Section length
  01 00 00 00           # lists
  01 00 00 00           # elements
  # lists
  00 00 00 00           # first list
  01 00 00 00           # size: 1
  index(strNull,strFromSet,2)           # str
  # ranges
   # range @0
  75 1A 00 00           # start
  79 1A 00 00           # end
  block(usetEnd)

block(vars)                         # struct COMP_KMXPLUS_VARS {
  76 61 72 73                       #   KMX_DWORD header.ident;   // 0000 Section name - vars
  diff(vars,varsEnd)                #   KMX_DWORD header.size;    // 0004 Section length
  01 00 00 00                       #   KMX_DWORD markers - list 1 ['a']
  diff(varsBegin,varsEnd,16)        #   KMX_DWORD varCount

  block(varsBegin)
  # var 0
  00 00 00 00                       #   KMX_DWORD type = str
  index(strNull,strA,2)             #   KMXPLUS_STR id  'a'
  index(strNull,strAmarker,2)       #   KMXPLUS_STR value '\m{a}'
  00 00 00 00                       #   KMXPLUS_ELEM

  # var 1
  01 00 00 00                       #   KMX_DWORD type = set
  index(strNull,strVse,2)           #   KMXPLUS_STR id  'vse'
  index(strNull,strSet,2)           #   KMXPLUS_STR value 'a b c'
  01 00 00 00                       #   KMXPLUS_ELEM elem 'a b c' see 'elemSet'

  # var 2
  00 00 00 00                       #   KMX_DWORD type = string
  index(strNull,strVst,2)           #   KMXPLUS_STR id  'vst'
  index(strNull,strSet2,2)          #   KMXPLUS_STR value 'abc'
  00 00 00 00                       #   KMXPLUS_ELEM elem

  # var 3
  02 00 00 00                       #   KMX_DWORD type = string
  index(strNull,strVus,2)           #   KMXPLUS_STR id  'vus'
  index(strNull,strUSet,2)          #   KMXPLUS_STR value '[abc]'
  00 00 00 00                       #   KMXPLUS_ELEM elem
block(varsEnd)

block(eof)   # end of file
