UNPKG

@iwater/mdict-ts

Version:

mdict (*.mdx, *.mdd) file reader

127 lines (126 loc) 5.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MDictParser = void 0; const util_1 = require("./util"); const crypt_1 = require("./crypt"); const Scan_1 = require("./Scan"); class MDictParser { constructor(file) { this.RECORD_BLOCK_TABLE = util_1.createRecordBlockTable(); this.file = file; this.ext = util_1.getExtension(file); this.read = util_1.readFile.bind(null, this.file); } async init() { let pos = 0; await this.read(0, 4).then(async (data) => { const headerLength = new util_1.dataView(data).getUint32(0); const res = await this.read(4, headerLength + 48); const headerRemainLen = await this.read_header_sect(res, headerLength); pos += headerRemainLen + 4; return this.read_keyword_summary(res, headerRemainLen); }).then(async (keyword) => { pos += keyword.len; const res = await this.read(pos, keyword.key_index_comp_len); this.KEY_INDEX = await this.read_keyword_index(res, keyword); pos += keyword.key_index_comp_len; this.slicedKeyBlock = this.read(pos, keyword.key_blocks_len); pos += keyword.key_blocks_len; return this.read_record_summary(await this.read(pos, 32), pos); }).then(async (recordSummary) => { pos += recordSummary.len; await this.read_record_block(await this.read(pos, recordSummary.index_len), recordSummary); }); } read_header_sect(input, len) { let header_str = util_1.readUTF16(input, len).replace(/\0$/, ''); const doc = util_1.parseXml(header_str); let xml = doc.getElementsByTagName('Dictionary')[0]; if (!xml) xml = doc.getElementsByTagName('Library_Data')[0]; let attrs = { GeneratedByEngineVersion: '', RequiredEngineVersion: '', Encrypted: 0, Format: '', CreationDate: '', Compact: '', Compat: '', KeyCaseSensitive: '', Description: '', Title: '', DataSourceFormat: '', StyleSheet: '', RegisterBy: '', RegCode: '', StripKey: '' }; for (let i = 0, item; i < xml.attributes.length; i++) { item = xml.attributes[i]; attrs[item.nodeName] = item.nodeValue; } this.headerSection = attrs; attrs.Encrypted = parseInt(String(attrs.Encrypted), 10) || 0; this.scan = new Scan_1.Scan(attrs); if (attrs.Encrypted & 0x02) this.keywordIndexDecryptor = crypt_1.decrypt; this.adaptKey = util_1.getAdaptKey(attrs, this.ext); this.StyleSheet = util_1.getGlobalStyle(attrs.StyleSheet); return len + 4; } read_keyword_summary(input, offset) { const scanner = this.scan.init(input).forward(offset); return { num_blocks: scanner.readNum(), num_entries: scanner.readNum(), key_index_decomp_len: scanner.v2 && scanner.readNum(), key_index_comp_len: scanner.readNum(), key_blocks_len: scanner.readNum(), chksum: scanner.checksumV2(), len: scanner.offset - offset, }; } read_keyword_index(input, keyword_summary) { let scanner = this.scan.init(input).readBlock(keyword_summary.key_index_comp_len, keyword_summary.key_index_decomp_len, this.keywordIndexDecryptor), keyword_index = Array(keyword_summary.num_blocks), offset = 0; for (let i = 0, size; i < keyword_summary.num_blocks; i++) { keyword_index[i] = { num_entries: [scanner.readNum(), size = scanner.readShort()][0], first_word: [scanner.readTextSized(size), size = scanner.readShort()][0], last_word: scanner.readTextSized(size), comp_size: size = scanner.readNum(), decomp_size: scanner.readNum(), offset: offset, index: i }; offset += size; } return keyword_index; } read_record_summary(input, pos) { let scanner = this.scan.init(input), record_summary = { num_blocks: scanner.readNum(), num_entries: scanner.readNum(), index_len: scanner.readNum(), blocks_len: scanner.readNum(), len: scanner.offset, block_pos: 0 }; record_summary.block_pos = pos + record_summary.index_len + record_summary.len; return record_summary; } read_record_block(input, record_summary) { let scanner = this.scan.init(input), size = record_summary.num_blocks, record_index = Array(size), p0 = record_summary.block_pos, p1 = 0; this.RECORD_BLOCK_TABLE.alloc(size + 1); for (let i = 0, rdx; i < size; i++) { record_index[i] = rdx = { comp_size: scanner.readNum(), decomp_size: scanner.readNum() }; this.RECORD_BLOCK_TABLE.put(p0, p1); p0 += rdx.comp_size; p1 += rdx.decomp_size; } this.RECORD_BLOCK_TABLE.put(p0, p1); } } exports.MDictParser = MDictParser;