mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-10 10:55:33 +00:00
refactor(common): consolidate header struct to kmx-plus-file.ts
Consolidate the header structure in KMX+ to make it easier to add a version value to the header for v19+ KMX+ files; also DRYs out the header definitions a little.
This commit is contained in:
parent
39951f15f6
commit
b4bb07ecc4
15 changed files with 89 additions and 65 deletions
|
|
@ -61,6 +61,8 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
public readonly COMP_PLUS_VARS: any;
|
||||
public readonly COMP_PLUS_VARS_ITEM: any;
|
||||
|
||||
private readonly COMP_PLUS_SectionHeader: any;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
// Binary-correct structures matching kmx_plus.h
|
||||
|
|
@ -73,6 +75,14 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
const CHAR32 = r.uint32le;
|
||||
const STR_OR_CHAR32_OR_USET = r.uint32le;
|
||||
const IDENT = r.uint32le;
|
||||
|
||||
// Section header - version dependent
|
||||
|
||||
this.COMP_PLUS_SectionHeader = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
});
|
||||
|
||||
// 'sect'
|
||||
|
||||
this.COMP_PLUS_SECT_ITEM = new r.Struct({
|
||||
|
|
@ -81,8 +91,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_SECT = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
total: r.uint32le,
|
||||
count: r.uint32le,
|
||||
items: new r.Array(this.COMP_PLUS_SECT_ITEM, 'count')
|
||||
|
|
@ -98,8 +107,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_DISP = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
count: r.uint32le,
|
||||
baseCharacter: CHAR32,
|
||||
items: new r.Array(this.COMP_PLUS_DISP_ITEM, 'count'),
|
||||
|
|
@ -118,8 +126,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_ELEM = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
count: r.uint32le,
|
||||
strings: new r.Array(this.COMP_PLUS_ELEM_STRING, 'count')
|
||||
// + variable subtable: Element data (see KMXPlusBuilder.emitElements())
|
||||
|
|
@ -155,8 +162,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_LAYR = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
listCount: r.uint32le,
|
||||
layerCount: r.uint32le,
|
||||
rowCount: r.uint32le,
|
||||
|
|
@ -199,8 +205,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_KEYS = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
keyCount: r.uint32le,
|
||||
flicksCount: r.uint32le,
|
||||
flickCount: r.uint32le,
|
||||
|
|
@ -223,8 +228,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_LIST = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
listCount: r.uint32le,
|
||||
indexCount: r.uint32le,
|
||||
lists: new r.Array(this.COMP_PLUS_LIST_LIST, 'listCount'),
|
||||
|
|
@ -236,8 +240,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
this.COMP_PLUS_LOCA_ITEM = r.uint32le; //str
|
||||
|
||||
this.COMP_PLUS_LOCA = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
count: r.uint32le,
|
||||
items: new r.Array(this.COMP_PLUS_LOCA_ITEM, 'count')
|
||||
});
|
||||
|
|
@ -245,8 +248,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
// 'meta'
|
||||
|
||||
this.COMP_PLUS_META = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
author: STR_REF, //str
|
||||
conform: STR_REF, //str
|
||||
layout: STR_REF, //str
|
||||
|
|
@ -270,8 +272,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_STRS = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
count: r.uint32le,
|
||||
items: new r.Array(this.COMP_PLUS_STRS_ITEM, 'count')
|
||||
// + variable subtable: String data (see KMXPlusBuilder.emitStrings())
|
||||
|
|
@ -298,8 +299,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_TRAN = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
groupCount: r.uint32le,
|
||||
transformCount: r.uint32le,
|
||||
reorderCount: r.uint32le,
|
||||
|
|
@ -322,8 +322,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_USET = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
usetCount: r.uint32le,
|
||||
rangeCount: r.uint32le,
|
||||
usets: new r.Array(this.COMP_PLUS_USET_USET, 'usetCount'),
|
||||
|
|
@ -340,8 +339,7 @@ export class KMXPlusFileFormat extends KMXFile {
|
|||
});
|
||||
|
||||
this.COMP_PLUS_VARS = new r.Struct({
|
||||
ident: IDENT,
|
||||
size: r.uint32le,
|
||||
header: this.COMP_PLUS_SectionHeader,
|
||||
markers: LIST_REF,
|
||||
varCount: r.uint32le,
|
||||
varEntries: new r.Array(this.COMP_PLUS_VARS_ITEM, 'varCount'),
|
||||
|
|
|
|||
|
|
@ -30,8 +30,10 @@ export function build_disp(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS): BUILD
|
|||
}
|
||||
|
||||
const disp: BUILDER_DISP = {
|
||||
ident: constants.hex_section_id(constants.section.disp),
|
||||
size: constants.length_disp + constants.length_disp_item * kmxplus.disp.disps.length,
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.disp),
|
||||
size: constants.length_disp + constants.length_disp_item * kmxplus.disp.disps.length,
|
||||
},
|
||||
_offset: 0,
|
||||
count: kmxplus.disp.disps.length,
|
||||
baseCharacter: build_strs_index(sect_strs, kmxplus.disp.baseCharacter),
|
||||
|
|
|
|||
|
|
@ -48,8 +48,10 @@ function binaryElemCompare(a: BUILDER_ELEM_STRING, b: BUILDER_ELEM_STRING): numb
|
|||
|
||||
export function build_elem(source_elem: Elem, sect_strs: BUILDER_STRS, sect_uset: BUILDER_USET): BUILDER_ELEM {
|
||||
const result: BUILDER_ELEM = {
|
||||
ident: constants.hex_section_id(constants.section.elem),
|
||||
size: 0, // finalized below
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.elem),
|
||||
size: 0, // finalized below
|
||||
},
|
||||
_offset: 0,
|
||||
count: source_elem.strings.length,
|
||||
strings: [], // finalized below
|
||||
|
|
@ -98,7 +100,7 @@ export function build_elem(source_elem: Elem, sect_strs: BUILDER_STRS, sect_uset
|
|||
}
|
||||
}
|
||||
|
||||
result.size = offset;
|
||||
result.header.size = offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,8 +76,10 @@ export function build_keys(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
|
|||
}
|
||||
|
||||
const keys: BUILDER_KEYS = {
|
||||
ident: constants.hex_section_id(constants.section.keys),
|
||||
size: 0,
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.keys),
|
||||
size: 0,
|
||||
},
|
||||
keyCount: kmxplus.keys.keys.length,
|
||||
flicksCount: kmxplus.keys.flicks.length,
|
||||
flickCount: 0,
|
||||
|
|
@ -169,7 +171,7 @@ export function build_keys(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
|
|||
(constants.length_keys_flick_element * keys.flickCount) +
|
||||
(constants.length_keys_flick_list * keys.flicksCount) +
|
||||
(constants.length_keys_kmap * keys.kmapCount);
|
||||
keys.size = offset;
|
||||
keys.header.size = offset;
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,8 +72,10 @@ export function build_layr(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
|
|||
}
|
||||
|
||||
const layr: BUILDER_LAYR = {
|
||||
ident: constants.hex_section_id(constants.section.layr),
|
||||
size: constants.length_layr,
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.layr),
|
||||
size: constants.length_layr,
|
||||
},
|
||||
_offset: 0,
|
||||
listCount: kmxplus.layr.lists.length,
|
||||
layerCount: 0, // calculated below
|
||||
|
|
@ -155,6 +157,6 @@ export function build_layr(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_l
|
|||
(constants.length_layr_entry * layr.layerCount) +
|
||||
(constants.length_layr_row * layr.rowCount) +
|
||||
(constants.length_layr_key * layr.keyCount);
|
||||
layr.size = offset;
|
||||
layr.header.size = offset;
|
||||
return layr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,8 +44,10 @@ export function build_list(source_list: List, sect_strs: BUILDER_STRS): BUILDER_
|
|||
}
|
||||
|
||||
const result: BUILDER_LIST = {
|
||||
ident: constants.hex_section_id(constants.section.list),
|
||||
size: 0,
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.list),
|
||||
size: 0,
|
||||
},
|
||||
_offset: 0,
|
||||
listCount: source_list.lists.length,
|
||||
indexCount: 0,
|
||||
|
|
@ -77,7 +79,7 @@ export function build_list(source_list: List, sect_strs: BUILDER_STRS): BUILDER_
|
|||
const offset = constants.length_list +
|
||||
(constants.length_list_item * result.listCount) +
|
||||
(constants.length_list_index * result.indexCount);
|
||||
result.size = offset;
|
||||
result.header.size = offset;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,10 @@ export interface BUILDER_LOCA extends BUILDER_SECTION {
|
|||
|
||||
export function build_loca(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS): BUILDER_LOCA {
|
||||
const loca: BUILDER_LOCA = {
|
||||
ident: constants.hex_section_id(constants.section.loca),
|
||||
size: constants.length_loca + constants.length_loca_item * kmxplus.loca.locales.length,
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.loca),
|
||||
size: constants.length_loca + constants.length_loca_item * kmxplus.loca.locales.length,
|
||||
},
|
||||
_offset: 0,
|
||||
count: kmxplus.loca.locales.length,
|
||||
items: []
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ export interface BUILDER_META extends BUILDER_SECTION {
|
|||
|
||||
export function build_meta(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS): BUILDER_META {
|
||||
return {
|
||||
ident: constants.hex_section_id(constants.section.meta),
|
||||
size: constants.length_meta,
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.meta),
|
||||
size: constants.length_meta,
|
||||
},
|
||||
_offset: 0,
|
||||
author: build_strs_index(sect_strs, kmxplus.meta.author),
|
||||
conform: build_strs_index(sect_strs, kmxplus.meta.conform),
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ export interface BUILDER_SECT extends BUILDER_SECTION {
|
|||
|
||||
export function build_sect(): BUILDER_SECT {
|
||||
return {
|
||||
ident: constants.hex_section_id(constants.section.sect),
|
||||
size: 0, // finalized later
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.sect),
|
||||
size: 0, // finalized later
|
||||
},
|
||||
_offset: 0,
|
||||
total: 0, // finalized later
|
||||
count: 0, // finalized later
|
||||
|
|
|
|||
|
|
@ -30,8 +30,10 @@ export interface BUILDER_STRS extends BUILDER_SECTION {
|
|||
|
||||
export function build_strs(source_strs: Strs): BUILDER_STRS {
|
||||
const result: BUILDER_STRS = {
|
||||
ident: constants.hex_section_id(constants.section.strs),
|
||||
size: 0, // finalized later
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.strs),
|
||||
size: 0, // finalized later
|
||||
},
|
||||
_offset: 0,
|
||||
count: source_strs.strings.length,
|
||||
items: [], // filled below
|
||||
|
|
@ -46,7 +48,7 @@ export function build_strs(source_strs: Strs): BUILDER_STRS {
|
|||
item.offset = offset;
|
||||
offset += item.length * 2 + 2; /* UTF-16 code units + sizeof null terminator */
|
||||
}
|
||||
result.size = offset;
|
||||
result.header.size = offset;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,8 +48,10 @@ export function build_tran(source_tran: Tran | Bksp, sect_strs: BUILDER_STRS, se
|
|||
}
|
||||
|
||||
const tran: BUILDER_TRAN = {
|
||||
ident: constants.hex_section_id(source_tran.id),
|
||||
size: 0, // need to compute total transforms + reorders
|
||||
header: {
|
||||
ident: constants.hex_section_id(source_tran.id),
|
||||
size: 0, // need to compute total transforms + reorders
|
||||
},
|
||||
_offset: 0,
|
||||
groupCount: source_tran.groups.length,
|
||||
transformCount: 0,
|
||||
|
|
@ -94,7 +96,7 @@ export function build_tran(source_tran: Tran | Bksp, sect_strs: BUILDER_STRS, se
|
|||
tran.transformCount = tran.transforms.length;
|
||||
tran.reorderCount = tran.reorders.length;
|
||||
|
||||
tran.size = constants.length_tran +
|
||||
tran.header.size = constants.length_tran +
|
||||
(constants.length_tran_group * source_tran.groups.length) +
|
||||
(constants.length_tran_transform * tran.transforms.length) +
|
||||
(constants.length_tran_reorder * tran.reorders.length);
|
||||
|
|
|
|||
|
|
@ -57,10 +57,12 @@ export function build_uset(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS ) : BUI
|
|||
});
|
||||
|
||||
const uset: BUILDER_USET = {
|
||||
ident: constants.hex_section_id(constants.section.uset),
|
||||
size: constants.length_uset +
|
||||
(constants.length_uset_uset * usets.length) +
|
||||
(constants.length_uset_range * ranges.length),
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.uset),
|
||||
size: constants.length_uset +
|
||||
(constants.length_uset_uset * usets.length) +
|
||||
(constants.length_uset_range * ranges.length),
|
||||
},
|
||||
usetCount: usets.length,
|
||||
rangeCount: ranges.length,
|
||||
usets,
|
||||
|
|
|
|||
|
|
@ -46,9 +46,11 @@ export function build_vars(kmxplus: KMXPlusData, sect_strs: BUILDER_STRS, sect_e
|
|||
});
|
||||
|
||||
const vars: BUILDER_VARS = {
|
||||
ident: constants.hex_section_id(constants.section.vars),
|
||||
size: constants.length_vars +
|
||||
(constants.length_vars_item * kmxplus.vars.totalCount()),
|
||||
header: {
|
||||
ident: constants.hex_section_id(constants.section.vars),
|
||||
size: constants.length_vars +
|
||||
(constants.length_vars_item * kmxplus.vars.totalCount()),
|
||||
},
|
||||
_offset: 0,
|
||||
markers: build_list_index(sect_list, kmxplus.vars.markers),
|
||||
varCount: kmxplus.vars.totalCount(),
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ export type BUILDER_IDENT = number;
|
|||
export type BUILDER_U32CHAR = number;
|
||||
|
||||
export interface BUILDER_SECTION {
|
||||
ident: BUILDER_IDENT;
|
||||
size: number;
|
||||
header: {
|
||||
ident: BUILDER_IDENT;
|
||||
size: number;
|
||||
};
|
||||
_offset: number; // used only for building the output
|
||||
}
|
||||
;
|
||||
|
|
|
|||
|
|
@ -115,9 +115,9 @@ export default class KMXPlusBuilder {
|
|||
}
|
||||
});
|
||||
|
||||
this.sect.sect.size = constants.length_sect + constants.length_sect_item * this.sect.sect.count;
|
||||
this.sect.sect.header.size = constants.length_sect + constants.length_sect_item * this.sect.sect.count;
|
||||
|
||||
let offset = this.sect.sect.size;
|
||||
let offset = this.sect.sect.header.size;
|
||||
// Note: in order! Everyone's here except 'sect' which is at offset 0
|
||||
offset = this.finalize_sect_item(this.sect.bksp, offset);
|
||||
offset = this.finalize_sect_item(this.sect.disp, offset);
|
||||
|
|
@ -141,16 +141,16 @@ export default class KMXPlusBuilder {
|
|||
return offset;
|
||||
}
|
||||
sect._offset = offset;
|
||||
this.sect.sect.items.push({sect: sect.ident, offset: offset});
|
||||
return offset + sect.size;
|
||||
this.sect.sect.items.push({sect: sect.header.ident, offset: offset});
|
||||
return offset + sect.header.size;
|
||||
}
|
||||
|
||||
private emitSection(file: Uint8Array, comp: any, sect: BUILDER_SECTION) {
|
||||
if(sect) {
|
||||
const buf = comp.toBuffer(sect);
|
||||
if (buf.length > sect.size) {
|
||||
if (buf.length > sect.header.size) {
|
||||
// buf.length may be < sect.size if there is a variable part (i.e. elem)
|
||||
throw new RangeError(`Internal Error: Section ${constants.str_section_id(sect.ident)} claimed size ${sect.size} but produced buffer of size ${buf.length}.`);
|
||||
throw new RangeError(`Internal Error: Section ${constants.str_section_id(sect.header.ident)} claimed size ${sect.header.size} but produced buffer of size ${buf.length}.`);
|
||||
}
|
||||
file.set(buf, sect._offset);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue