def parse_header(self): self.magic = self.data[:4] self.version = int.from_bytes(self.data[4:8], 'little') self.rule_count = int.from_bytes(self.data[8:12], 'little') # ... parse rules When shaping Arabic text, after mandatory shaping, apply optional rules:
# Write header + body with open(output_bin_path, 'wb') as out: out.write(magic) out.write(struct.pack('<I', version)) out.write(struct.pack('<I', rule_count)) out.write(struct.pack('<I', 16)) # offset to body (after header) out.write(body) fg-optional-arabic.bin
// ... load rule table from body_offset fclose(f); return hdr; def parse_header(self): self
# Write each rule as: input_len (1B), inputs (4B each), output_len (1B), outputs (4B each), priority (1B) for rule in rules: inputs = rule['input'] outputs = rule['output'] if isinstance(rule['output'], list) else [rule['output']] 'little') self.rule_count = int.from_bytes(self.data[8:12]
import json import struct def build_binary(rules_json_path, output_bin_path): with open(rules_json_path, 'r', encoding='utf-8') as f: data = json.load(f)
body.append(len(inputs)) for ch in inputs: body.extend(struct.pack('<I', ch)) # Unicode codepoint
# Prepare header magic = b'FGOA' version = data['version'] rules = data['optional_features'] rule_count = len(rules)