fix: #51 mmkv parsing
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
鲁树人 2023-10-11 21:35:21 +01:00
parent d3385c1902
commit 2fb345a177
5 changed files with 56 additions and 22 deletions

View File

@ -69,18 +69,21 @@ export class MMKVParser {
return bytesToUTF8String(data).normalize();
}
public readVariantString() {
public readOptionalString() {
// Container [
// len: int,
// data: variant
// ]
const containerLen = this.readInt();
if (containerLen === 0) {
return null;
}
const newOffset = this.offset + containerLen;
const result = this.readString();
if (newOffset !== this.offset) {
const expected = formatHex(newOffset);
const actual = formatHex(this.offset);
throw new Error(`readVariantString failed: offset does mismatch (expect: ${expected}, actual: ${actual})`);
throw new Error(`readVariantString failed: offset mismatch (expect: ${expected}, actual: ${actual})`);
}
return result;
}
@ -99,13 +102,15 @@ export class MMKVParser {
const result = new Map<string, string>();
while (!mmkv.eof) {
const key = mmkv.readString();
const value = mmkv.readVariantString();
result.set(key, value);
const value = mmkv.readOptionalString();
if (value) {
result.set(key, value);
}
}
return result;
}
public static parseKuwoEKey(view: DataView) {
public static parseKuwoEKey(view: DataView): Omit<StagingKWMv2Key, 'id'>[] {
const mmkv = new MMKVParser(view);
const result: Omit<StagingKWMv2Key, 'id'>[] = [];
while (!mmkv.eof) {
@ -117,8 +122,10 @@ export class MMKVParser {
}
const [_, rid, quality] = idMatch;
const ekey = mmkv.readVariantString();
result.push({ rid, quality, ekey });
const ekey = mmkv.readOptionalString();
if (ekey) {
result.push({ rid, quality, ekey });
}
}
return result;
}

View File

@ -1,19 +1,46 @@
import { MMKVParser } from '../MMKVParser';
import { readFileSync } from 'node:fs';
test('parse mmkv file as expected', () => {
const buff = readFileSync(__dirname + '/__fixture__/test.mmkv');
const view = new DataView(buff.buffer.slice(buff.byteOffset, buff.byteOffset + buff.byteLength));
expect(MMKVParser.toStringMap(view)).toEqual(
new Map([
['key', 'value'],
[
'Lorem Ipsum',
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' +
'Vestibulum congue volutpat metus non molestie. Quisque id est sapien. ' +
'Fusce eget tristique sem. Donec tellus lacus, viverra sed lectus eget, elementum ultrices dolor. ' +
'Integer non urna justo.',
],
])
);
const makeViewFromBuffer = (buff: Buffer) =>
new DataView(buff.buffer.slice(buff.byteOffset, buff.byteOffset + buff.byteLength));
test('parse qm mmkv file', () => {
const view = makeViewFromBuffer(readFileSync(__dirname + '/__fixture__/qm.mmkv'));
expect(Object.fromEntries(MMKVParser.toStringMap(view).entries())).toMatchInlineSnapshot(`
{
"Lorem Ipsum": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum congue volutpat metus non molestie. Quisque id est sapien. Fusce eget tristique sem. Donec tellus lacus, viverra sed lectus eget, elementum ultrices dolor. Integer non urna justo.",
"key": "value",
}
`);
});
test('parse qm mmkv file with optional str', () => {
const view = makeViewFromBuffer(readFileSync(__dirname + '/__fixture__/qm_optional.mmkv'));
expect(Object.fromEntries(MMKVParser.toStringMap(view).entries())).toMatchInlineSnapshot(`
{
"key": "value",
"key2": "value2",
}
`);
});
test('parse kuwo mmkv file', () => {
const view = makeViewFromBuffer(readFileSync(__dirname + '/__fixture__/kuwo.mmkv'));
expect(MMKVParser.parseKuwoEKey(view)).toMatchInlineSnapshot(`
[
{
"ekey": "xyz123",
"quality": "20201kmflac",
"rid": "1234567",
},
]
`);
});
test('throw error on broken file', () => {
const view = makeViewFromBuffer(
Buffer.from([0x27, 0x00, 0x00, 0x00, 0x7f, 0x03, 0x6b, 0x65, 0x79, 0x06, 0x07, 0x62, 0x61, 0x64, 0xff, 0xff]),
);
expect(() => Object.fromEntries(MMKVParser.toStringMap(view).entries())).toThrow(/offset mismatch/i);
});

Binary file not shown.

Binary file not shown.