From 278d4e3a24fde3d036cd15090d63a76d5f7a6ad8 Mon Sep 17 00:00:00 2001 From: Borys Levytskyi Date: Thu, 4 May 2023 22:17:48 +0300 Subject: [PATCH] Fix issue with large binary numbers (#43) --- src/core/calc.test.ts | 2 + src/core/formatter.test.ts | 8 +++ src/expression/NumericOperand.test.ts | 17 +++++- src/expression/NumericOperand.ts | 16 +++++- .../BitwiseOperationExpressionView.tsx | 5 +- src/shell/AppState.ts | 2 +- src/shell/components/WhatsNewResultView.tsx | 6 +++ tsconfig.json | 52 +++++++++---------- 8 files changed, 76 insertions(+), 32 deletions(-) diff --git a/src/core/calc.test.ts b/src/core/calc.test.ts index 7a828e0..97e1ed3 100644 --- a/src/core/calc.test.ts +++ b/src/core/calc.test.ts @@ -1,11 +1,13 @@ import calc from './calc'; import { BitwiseOperationExpression, NumericOperand, ExpressionOperand } from '../expression/expression'; +import exp from 'constants'; describe("calc", () => { it('calculates number of bits', () => { expect(calc.numberOfBits(1)).toBe(1); expect(calc.numberOfBits(2)).toBe(2); expect(calc.numberOfBits(3)).toBe(2); + expect(calc.numberOfBits(68719476735)).toBe(36); }); it('calculates max number of bits', () => { diff --git a/src/core/formatter.test.ts b/src/core/formatter.test.ts index f0d16b1..9d08afa 100644 --- a/src/core/formatter.test.ts +++ b/src/core/formatter.test.ts @@ -7,6 +7,14 @@ describe("formatter", () => { expect(formatter.formatString(15, "bin")).toBe("1111"); }); + it('formats large binary number correctly', () => { + var decimal = 68719476735; + var binary = formatter.bin(68719476735); + var hex = formatter.formatString(decimal, 'hex'); + expect(binary).toBe('111111111111111111111111111111111111'); + expect(hex).toBe('fffffffff'); + }) + it('pads left', () => { expect(formatter.padLeft("1", 3, " ")).toBe(" 1"); }); diff --git a/src/expression/NumericOperand.test.ts b/src/expression/NumericOperand.test.ts index 6508d9e..22b46fa 100644 --- a/src/expression/NumericOperand.test.ts +++ b/src/expression/NumericOperand.test.ts @@ -1,4 +1,4 @@ -import NumericOperand from './NumericOperand'; +import NumericOperand, { INT_MAX_VALUE } from './NumericOperand'; it('parsed from string', () => { var op = NumericOperand.parse('123'); @@ -10,4 +10,17 @@ it('can get other kind', () => { var op = new NumericOperand(10, 'dec'); expect(op.getOtherBase('hex')).toBe('dec'); expect(op.getOtherBase('bin')).toBe('hex'); -}); \ No newline at end of file +}); + +it('negtive value binary string', () => { + expect(NumericOperand.toBaseString(-1, 'bin')).toBe('11111111111111111111111111111111'); +}); + +it('64 bit operand binary string', () => { + expect(NumericOperand.toBaseString(68719476735, 'bin')).toBe('111111111111111111111111111111111111'); +}); + +it('throws on negative 64 bit numbers', () => { + var bigN = -(INT_MAX_VALUE+1); + expect(() => new NumericOperand(bigN)).toThrowError("BitwiseCmd currently doesn't support 64 bit negative numbers such as " + bigN); +}) \ No newline at end of file diff --git a/src/expression/NumericOperand.ts b/src/expression/NumericOperand.ts index 371cd7b..3a6ee8c 100644 --- a/src/expression/NumericOperand.ts +++ b/src/expression/NumericOperand.ts @@ -3,6 +3,10 @@ import { ExpressionInputItem, NumberBase } from './expression-interfaces'; var globalId : number = 1; +const INT_MAX_VALUE = 2147483647; + +export {INT_MAX_VALUE}; + // Represents numeric value export default class NumericOperand implements ExpressionInputItem { id: number; @@ -17,6 +21,9 @@ export default class NumericOperand implements ExpressionInputItem { this.base = base || "dec"; this.lengthInBits = NumericOperand.getBitLength(this.value); this.isExpression = false; + + if(value < 0 && !NumericOperand.is32Bit(value)) + throw new Error("BitwiseCmd currently doesn't support 64 bit negative numbers such as " + value); } getLengthInBits() { @@ -102,7 +109,10 @@ export default class NumericOperand implements ExpressionInputItem { var hexVal = Math.abs(value).toString(16); return value >= 0 ? '0x' + hexVal : '-0x' + hexVal; case 'bin': - return (value>>>0).toString(2); + // >>> 0 is used to get an actual bit representation of the negative numbers + // https://stackoverflow.com/questions/5747123/strange-javascript-operator-expr-0 + const is32Bit = NumericOperand.is32Bit(value); + return (is32Bit && value < 0 ? (value >>> 0) : value).toString(2); case 'dec': return value.toString(10); default: @@ -113,4 +123,8 @@ export default class NumericOperand implements ExpressionInputItem { static toHexString (hex : string) { return hex.indexOf('-') === 0 ? '-0x' + hex.substr(1) : '0x' + hex; }; + + static is32Bit(n: number) { + return Math.abs(n) <= INT_MAX_VALUE + } } \ No newline at end of file diff --git a/src/expression/components/BitwiseOperationExpressionView.tsx b/src/expression/components/BitwiseOperationExpressionView.tsx index 4da004a..6b05d45 100644 --- a/src/expression/components/BitwiseOperationExpressionView.tsx +++ b/src/expression/components/BitwiseOperationExpressionView.tsx @@ -85,8 +85,9 @@ class ExpressionRow extends React.Component { ;; } - getBinaryString() : string { - return this.props.expressionItem.evaluate().toBinaryString(); + getBinaryString() : string { + var binary = this.props.expressionItem.evaluate().toBinaryString(); + return binary; } getLabel(): string { diff --git a/src/shell/AppState.ts b/src/shell/AppState.ts index 3b10bb7..392fc51 100644 --- a/src/shell/AppState.ts +++ b/src/shell/AppState.ts @@ -1,6 +1,6 @@ import log from 'loglevel'; -const APP_VERSION = 7; +const APP_VERSION = 8; export type PersistedAppData = { emphasizeBytes: boolean; diff --git a/src/shell/components/WhatsNewResultView.tsx b/src/shell/components/WhatsNewResultView.tsx index 57d6230..326ef36 100644 --- a/src/shell/components/WhatsNewResultView.tsx +++ b/src/shell/components/WhatsNewResultView.tsx @@ -6,6 +6,12 @@ function WhatsnewResultView() { return

Changelog

+
+

+ Jul 24th, 2021
+ Fixed bug with incorrect binary representation of 64 bit numbers. Negative 64 bit numbers currently are not supported by BitwiseCmd. +

+

Jul 24th, 2021

    diff --git a/tsconfig.json b/tsconfig.json index 16fff78..f199ca8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,26 +1,26 @@ -{ - "compilerOptions": { - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" - }, - "include": [ - "src" - ] -} +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve" + }, + "include": [ + "src" + ] +}