feat: add local OneNote and ONEPKG reader
This commit is contained in:
93
tests/file-node.test.ts
Normal file
93
tests/file-node.test.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { DesktopFileNodeParser } from '../src/onenote/onestore/file-node.js';
|
||||
import { OneNoteParserError } from '../src/onenote/parser/error.js';
|
||||
import { resolveParserLimits } from '../src/onenote/parser/limits.js';
|
||||
|
||||
const MAGIC = 0xa4567ab1f5f7f4c4n;
|
||||
const FOOTER = 0x8bc215c38233ba4bn;
|
||||
|
||||
describe('DesktopFileNodeParser', () => {
|
||||
it('rejects a multi-fragment cycle immediately', () => {
|
||||
const bytes = new Uint8Array(72);
|
||||
writeFragment(bytes, 0, 0x10, 0, 36);
|
||||
writeFragment(bytes, 36, 0x10, 1, 0);
|
||||
|
||||
const parser = new DesktopFileNodeParser(bytes, resolveParserLimits());
|
||||
const parse = () =>
|
||||
parser.parseList({ offset: 0, size: 36, nil: false, zero: false });
|
||||
|
||||
expect(parse).toThrowError(OneNoteParserError);
|
||||
expect(parse).toThrow(/cycle/i);
|
||||
});
|
||||
|
||||
it('stops decoding at ChunkTerminatorFND and permits an opaque tail', () => {
|
||||
const bytes = new Uint8Array(52);
|
||||
const view = new DataView(bytes.buffer);
|
||||
view.setBigUint64(0, MAGIC, true);
|
||||
view.setUint32(8, 0x10, true);
|
||||
view.setUint32(12, 0, true);
|
||||
view.setUint32(16, 0x10ff, true); // id 0xff, declared size 4
|
||||
bytes.fill(0xa5, 20, 32); // deliberately not valid FileNode words
|
||||
view.setBigUint64(32, 0xffffffffffffffffn, true);
|
||||
view.setUint32(40, 0, true);
|
||||
view.setBigUint64(44, FOOTER, true);
|
||||
|
||||
const parser = new DesktopFileNodeParser(bytes, resolveParserLimits());
|
||||
const parsed = parser.parseList({
|
||||
offset: 0,
|
||||
size: bytes.length,
|
||||
nil: false,
|
||||
zero: false,
|
||||
});
|
||||
|
||||
expect(parsed.nodes).toEqual([]);
|
||||
});
|
||||
|
||||
it('uses the transaction-log count to delimit nonzero fragment padding', () => {
|
||||
const bytes = new Uint8Array(52);
|
||||
const view = new DataView(bytes.buffer);
|
||||
view.setBigUint64(0, MAGIC, true);
|
||||
view.setUint32(8, 0x10, true);
|
||||
view.setUint32(12, 0, true);
|
||||
view.setUint32(16, 0x1004, true); // id 4, declared size 4
|
||||
bytes.fill(0xa5, 20, 32); // opaque tail without a terminator
|
||||
view.setBigUint64(32, 0xffffffffffffffffn, true);
|
||||
view.setUint32(40, 0, true);
|
||||
view.setBigUint64(44, FOOTER, true);
|
||||
|
||||
const parser = new DesktopFileNodeParser(
|
||||
bytes,
|
||||
resolveParserLimits(),
|
||||
new Map([[0x10, 1]])
|
||||
);
|
||||
const parsed = parser.parseList({
|
||||
offset: 0,
|
||||
size: bytes.length,
|
||||
nil: false,
|
||||
zero: false,
|
||||
});
|
||||
|
||||
expect(parsed.nodes.map(({ id }) => id)).toEqual([0x004]);
|
||||
});
|
||||
});
|
||||
|
||||
function writeFragment(
|
||||
bytes: Uint8Array,
|
||||
offset: number,
|
||||
listId: number,
|
||||
sequence: number,
|
||||
nextOffset: number
|
||||
): void {
|
||||
const view = new DataView(bytes.buffer, offset, 36);
|
||||
view.setBigUint64(0, MAGIC, true);
|
||||
view.setUint32(8, listId, true);
|
||||
view.setUint32(12, sequence, true);
|
||||
view.setBigUint64(16, BigInt(nextOffset), true);
|
||||
view.setUint32(24, 36, true);
|
||||
view.setBigUint64(28, FOOTER, true);
|
||||
}
|
||||
Reference in New Issue
Block a user