fix: #51 mmkv parsing
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
d3385c1902
commit
2fb345a177
@ -69,18 +69,21 @@ export class MMKVParser {
|
|||||||
return bytesToUTF8String(data).normalize();
|
return bytesToUTF8String(data).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public readVariantString() {
|
public readOptionalString() {
|
||||||
// Container [
|
// Container [
|
||||||
// len: int,
|
// len: int,
|
||||||
// data: variant
|
// data: variant
|
||||||
// ]
|
// ]
|
||||||
const containerLen = this.readInt();
|
const containerLen = this.readInt();
|
||||||
|
if (containerLen === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const newOffset = this.offset + containerLen;
|
const newOffset = this.offset + containerLen;
|
||||||
const result = this.readString();
|
const result = this.readString();
|
||||||
if (newOffset !== this.offset) {
|
if (newOffset !== this.offset) {
|
||||||
const expected = formatHex(newOffset);
|
const expected = formatHex(newOffset);
|
||||||
const actual = formatHex(this.offset);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
@ -99,13 +102,15 @@ export class MMKVParser {
|
|||||||
const result = new Map<string, string>();
|
const result = new Map<string, string>();
|
||||||
while (!mmkv.eof) {
|
while (!mmkv.eof) {
|
||||||
const key = mmkv.readString();
|
const key = mmkv.readString();
|
||||||
const value = mmkv.readVariantString();
|
const value = mmkv.readOptionalString();
|
||||||
result.set(key, value);
|
if (value) {
|
||||||
|
result.set(key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static parseKuwoEKey(view: DataView) {
|
public static parseKuwoEKey(view: DataView): Omit<StagingKWMv2Key, 'id'>[] {
|
||||||
const mmkv = new MMKVParser(view);
|
const mmkv = new MMKVParser(view);
|
||||||
const result: Omit<StagingKWMv2Key, 'id'>[] = [];
|
const result: Omit<StagingKWMv2Key, 'id'>[] = [];
|
||||||
while (!mmkv.eof) {
|
while (!mmkv.eof) {
|
||||||
@ -117,8 +122,10 @@ export class MMKVParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [_, rid, quality] = idMatch;
|
const [_, rid, quality] = idMatch;
|
||||||
const ekey = mmkv.readVariantString();
|
const ekey = mmkv.readOptionalString();
|
||||||
result.push({ rid, quality, ekey });
|
if (ekey) {
|
||||||
|
result.push({ rid, quality, ekey });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,46 @@
|
|||||||
import { MMKVParser } from '../MMKVParser';
|
import { MMKVParser } from '../MMKVParser';
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
|
|
||||||
test('parse mmkv file as expected', () => {
|
const makeViewFromBuffer = (buff: Buffer) =>
|
||||||
const buff = readFileSync(__dirname + '/__fixture__/test.mmkv');
|
new DataView(buff.buffer.slice(buff.byteOffset, buff.byteOffset + buff.byteLength));
|
||||||
const view = new DataView(buff.buffer.slice(buff.byteOffset, buff.byteOffset + buff.byteLength));
|
|
||||||
expect(MMKVParser.toStringMap(view)).toEqual(
|
test('parse qm mmkv file', () => {
|
||||||
new Map([
|
const view = makeViewFromBuffer(readFileSync(__dirname + '/__fixture__/qm.mmkv'));
|
||||||
['key', 'value'],
|
expect(Object.fromEntries(MMKVParser.toStringMap(view).entries())).toMatchInlineSnapshot(`
|
||||||
[
|
{
|
||||||
'Lorem Ipsum',
|
"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.",
|
||||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' +
|
"key": "value",
|
||||||
'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.',
|
});
|
||||||
],
|
|
||||||
])
|
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);
|
||||||
});
|
});
|
||||||
|
BIN
src/util/__tests__/__fixture__/kuwo.mmkv
Normal file
BIN
src/util/__tests__/__fixture__/kuwo.mmkv
Normal file
Binary file not shown.
BIN
src/util/__tests__/__fixture__/qm_optional.mmkv
Normal file
BIN
src/util/__tests__/__fixture__/qm_optional.mmkv
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user