diff --git a/src/__test__/integration.test.ts b/src/__test__/integration.test.ts index 5f1bf8e..31452f1 100755 --- a/src/__test__/integration.test.ts +++ b/src/__test__/integration.test.ts @@ -90,10 +90,10 @@ describe('mmdb lib', () => { float: 0, int32: 0, map: {}, - uint128: 0, + uint128: 0n, uint16: 0, uint32: 0, - uint64: 0, + uint64: 0n, utf8_string: '', }, }, @@ -116,10 +116,10 @@ describe('section: data', () => { float: 1.100000023841858, int32: -268435456, map: { mapX: { arrayX: [7, 8, 9], utf8_stringX: 'hello' } }, - uint128: '1329227995784915872903807060280344576', + uint128: 1329227995784915872903807060280344576n, uint16: 100, uint32: 268435456, - uint64: '1152921504606846976', + uint64: 1152921504606846976n, utf8_string: 'unicode! ☯ - ♫', }); }); @@ -134,10 +134,10 @@ describe('section: data', () => { float: 0, int32: 0, map: {}, - uint128: 0, + uint128: 0n, uint16: 0, uint32: 0, - uint64: 0, + uint64: 0n, utf8_string: '', }); }); @@ -217,10 +217,10 @@ describe('getWithPrefixLength', () => { utf8_stringX: 'hello', }, }, - uint128: '1329227995784915872903807060280344576', + uint128: 1329227995784915872903807060280344576n, uint16: 0x64, uint32: 268435456, - uint64: '1152921504606846976', + uint64: 1152921504606846976n, utf8_string: 'unicode! ☯ - ♫', }; const tests = [ diff --git a/src/decoder.test.ts b/src/decoder.test.ts index 1da7825..d091808 100644 --- a/src/decoder.test.ts +++ b/src/decoder.test.ts @@ -1,6 +1,4 @@ import { strict as assert } from 'assert'; -import fs from 'fs'; -import path from 'path'; import Decoder from './decoder'; describe('lib/decoder', () => { @@ -14,19 +12,6 @@ describe('lib/decoder', () => { }); }); - describe('decodeUint()', () => { - it('should return zero for unsupported int size', () => { - const decoder: any = new Decoder( - fs.readFileSync( - path.join(__dirname, '../test/data/test-data/GeoIP2-City-Test.mmdb') - ), - 1 - ); - - assert.strictEqual(decoder.decodeUint(1, 32), 0); - }); - }); - describe('decodeArray()', () => { const testCases = [ { @@ -407,20 +392,17 @@ describe('lib/decoder', () => { function generateLargeUintCases( bits: 64 | 128 - ): { expected: number | string; input: number[] }[] { + ): { expected: bigint; input: number[] }[] { const ctrlByte = bits === 64 ? 0x02 : 0x03; - const cases: { expected: number | string; input: number[] }[] = []; - - cases.push({ expected: 0, input: [0x00, ctrlByte] }); - cases.push({ expected: 500, input: [0x02, ctrlByte, 0x01, 0xf4] }); - cases.push({ expected: 10872, input: [0x02, ctrlByte, 0x2a, 0x78] }); + const cases = [ + { expected: 0n, input: [0x00, ctrlByte] }, + { expected: 500n, input: [0x02, ctrlByte, 0x01, 0xf4] }, + { expected: 10872n, input: [0x02, ctrlByte, 0x2a, 0x78] }, + ]; const maxBytes = bits / 8; for (let byteCount = 1; byteCount <= maxBytes; byteCount++) { - const expectedNum = (1n << BigInt(8 * byteCount)) - 1n; - // For some reason we convert big ints to strings in the decoder - const expectedValue = - byteCount <= 6 ? Number(expectedNum) : expectedNum.toString(); + const expectedValue = (1n << BigInt(8 * byteCount)) - 1n; const inputBytes: number[] = Array(byteCount).fill(0xff); const input = [byteCount, ctrlByte, ...inputBytes]; @@ -429,7 +411,7 @@ describe('lib/decoder', () => { return cases; } - describe('decodeUint() - uint64', () => { + describe('decodeBigUint() - uint64', () => { const testCases = generateLargeUintCases(64); for (const tc of testCases) { @@ -441,7 +423,7 @@ describe('lib/decoder', () => { } }); - describe('decodeUint() - uint128', () => { + describe('decodeBigUint() - uint128', () => { const testCases = generateLargeUintCases(128); for (const tc of testCases) { diff --git a/src/decoder.ts b/src/decoder.ts index 0e001a2..5dd71af 100755 --- a/src/decoder.ts +++ b/src/decoder.ts @@ -123,9 +123,9 @@ export default class Decoder { case DataType.Int32: return cursor(this.decodeInt32(offset, size), newOffset); case DataType.Uint64: - return cursor(this.decodeUint(offset, size), newOffset); + return cursor(this.decodeBigUint(offset, size), newOffset); case DataType.Uint128: - return cursor(this.decodeUint(offset, size), newOffset); + return cursor(this.decodeBigUint(offset, size), newOffset); } throw new Error('Unknown type ' + type + ' at offset ' + offset); @@ -269,32 +269,31 @@ export default class Decoder { return this.db.readInt32BE(offset); } - private decodeUint(offset: number, size: number) { + private decodeUint(offset: number, size: number): number { if (size === 0) { return 0; } - if (size <= 6) { + if (size <= 4) { return this.db.readUIntBE(offset, size); } - if (size == 8) { - return this.db.readBigUInt64BE(offset).toString(); - } - if (size > 16) { - return 0; - } - return this.decodeBigUint(offset, size); + + throw new Error(`Invalid size for unsigned integer: ${size}`); } private decodeString(offset: number, size: number) { return this.db.toString('utf8', offset, offset + size); } - private decodeBigUint(offset: number, size: number) { + private decodeBigUint(offset: number, size: number): bigint { + if (size > 16) { + throw new Error(`Invalid size for big unsigned integer: ${size}`); + } + let integer = 0n; for (let i = 0; i < size; i++) { integer <<= 8n; integer |= BigInt(this.db.readUInt8(offset + i)); } - return integer.toString(); + return integer; } } diff --git a/src/metadata.ts b/src/metadata.ts index ba1bbec..a51fb3b 100755 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -42,7 +42,7 @@ export const parseMetadata = (db: Buffer): Metadata => { return { binaryFormatMajorVersion: metadata.binary_format_major_version, binaryFormatMinorVersion: metadata.binary_format_minor_version, - buildEpoch: new Date(metadata.build_epoch * 1000), + buildEpoch: new Date(Number(metadata.build_epoch) * 1000), databaseType: metadata.database_type, description: metadata.description, ipVersion: metadata.ip_version,