Skip to content

Commit d10c472

Browse files
authored
fix: Fix string decoding in large mmdb files
Handle Large MMDBs
2 parents 684caeb + bd6ff13 commit d10c472

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

src/decoder.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,67 @@ describe('lib/decoder', () => {
352352
assert.deepStrictEqual(decoder.decode(0).value, tc.expected);
353353
});
354354
}
355+
356+
function createBufferWithStringAtOffset(
357+
offset: number,
358+
content: string
359+
): Buffer {
360+
const contentBuf = Buffer.from(content);
361+
const size = contentBuf.length;
362+
const padding = Buffer.alloc(offset);
363+
364+
let header: Buffer;
365+
if (size <= 0x1f) {
366+
header = Buffer.from([0x40 | size]);
367+
} else if (size <= 0xffff) {
368+
header = Buffer.from([0x40 | 0x1f, (size >> 8) & 0xff, size & 0xff]);
369+
} else {
370+
header = Buffer.from([
371+
0x5f,
372+
(size >> 24) & 0xff,
373+
(size >> 16) & 0xff,
374+
(size >> 8) & 0xff,
375+
size & 0xff,
376+
]);
377+
}
378+
379+
return Buffer.concat([padding, header, contentBuf]);
380+
}
381+
382+
const MAX_INT_32 = 2147483648;
383+
384+
it('should handle string just below 2^31 boundary', function () {
385+
this.timeout(15000);
386+
const offset = MAX_INT_32 - 16;
387+
const content = 'boundary test';
388+
389+
const buffer = createBufferWithStringAtOffset(offset, content);
390+
391+
const decoder = new Decoder(buffer);
392+
393+
const result = decoder.decode(offset);
394+
assert.strictEqual(result.value, content);
395+
assert(
396+
result.offset > offset,
397+
`Offset ${result.offset} should be > ${offset}`
398+
);
399+
});
400+
401+
it('should handle when string at offset >= 2^31', function () {
402+
this.timeout(15000);
403+
const offset = MAX_INT_32;
404+
const content = 'test';
405+
406+
const buffer = createBufferWithStringAtOffset(offset, content);
407+
const decoder = new Decoder(buffer);
408+
409+
const result = decoder.decode(offset);
410+
assert.strictEqual(result.value, content);
411+
assert(
412+
result.offset > offset,
413+
`Offset ${result.offset} should be > ${offset}`
414+
);
415+
});
355416
});
356417

357418
describe('decodeUint() - uint16', () => {

src/decoder.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ utils.assert(
66
'Apparently you are using old version of node. Please upgrade to node 10.4.x or above.'
77
);
88

9+
const MAX_INT_32 = 2_147_483_647;
10+
911
enum DataType {
1012
Extended = 0,
1113
Pointer = 1,
@@ -281,7 +283,10 @@ export default class Decoder {
281283
}
282284

283285
private decodeString(offset: number, size: number) {
284-
return this.db.toString('utf8', offset, offset + size);
286+
const newOffset = offset + size;
287+
return newOffset >= MAX_INT_32
288+
? this.db.subarray(offset, newOffset).toString('utf8')
289+
: this.db.toString('utf8', offset, newOffset);
285290
}
286291

287292
private decodeBigUint(offset: number, size: number): bigint {

0 commit comments

Comments
 (0)