From 128649076e47dc12c85a7c5f6731d27de72c09e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B2=81=E6=A0=91=E4=BA=BA?= Date: Wed, 11 Oct 2023 21:35:21 +0100 Subject: [PATCH] fix: #51 mmkv parsing --- src/util/MMKVParser.ts | 21 ++++--- src/util/__tests__/MMKVParser.test.ts | 57 +++++++++++++----- src/util/__tests__/__fixture__/kuwo.mmkv | Bin 0 -> 80 bytes .../__fixture__/{test.mmkv => qm.mmkv} | Bin .../__tests__/__fixture__/qm_optional.mmkv | Bin 0 -> 48 bytes 5 files changed, 56 insertions(+), 22 deletions(-) create mode 100644 src/util/__tests__/__fixture__/kuwo.mmkv rename src/util/__tests__/__fixture__/{test.mmkv => qm.mmkv} (100%) create mode 100644 src/util/__tests__/__fixture__/qm_optional.mmkv diff --git a/src/util/MMKVParser.ts b/src/util/MMKVParser.ts index f2a7d43..29b3ed5 100644 --- a/src/util/MMKVParser.ts +++ b/src/util/MMKVParser.ts @@ -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(); 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[] { const mmkv = new MMKVParser(view); const result: Omit[] = []; 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; } diff --git a/src/util/__tests__/MMKVParser.test.ts b/src/util/__tests__/MMKVParser.test.ts index e4eebcb..dc996ac 100644 --- a/src/util/__tests__/MMKVParser.test.ts +++ b/src/util/__tests__/MMKVParser.test.ts @@ -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); }); diff --git a/src/util/__tests__/__fixture__/kuwo.mmkv b/src/util/__tests__/__fixture__/kuwo.mmkv new file mode 100644 index 0000000000000000000000000000000000000000..e8261c648135016e1342aef57e95f5fbd4c12c26 GIT binary patch literal 80 zcmZ=^U|^`1DNap}Pt8uPR5mm+HZe6b*EKRQGBC`}P0LA4W@oFYtOAO2W#$!^B3 literal 0 HcmV?d00001 diff --git a/src/util/__tests__/__fixture__/test.mmkv b/src/util/__tests__/__fixture__/qm.mmkv similarity index 100% rename from src/util/__tests__/__fixture__/test.mmkv rename to src/util/__tests__/__fixture__/qm.mmkv diff --git a/src/util/__tests__/__fixture__/qm_optional.mmkv b/src/util/__tests__/__fixture__/qm_optional.mmkv new file mode 100644 index 0000000000000000000000000000000000000000..5e127d98a58d9199827dbea01f52f8be3afb7e77 GIT binary patch literal 48 wcmY#qU|^_c&Q7glV=YU}DNW@`%`GUYjL%HZ%P&f0U;#=Pv9p0?jQ)cF09