├── public └── favicon.ico ├── src ├── main.js ├── App.vue ├── components │ ├── BitBox.vue │ └── BitBench.vue └── bitstring.js ├── .gitignore ├── vite.config.js ├── index.html ├── README.md ├── package.json └── LICENSE /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/triq-org/bitbench/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | const app = createApp(App) 5 | app.mount('#app') 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig(({ mode }) => { 6 | return { 7 | base: mode == 'production' ? '/bitbench/' : '', 8 | server: { 9 | port: 8080, 10 | }, 11 | plugins: [vue()], 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | bitbench 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BitBench 2 | 3 | Visually dissect and analyze bit strings. 4 | 5 | ## Using the BitBench 6 | 7 | There is a hosted instance on http://triq.net/bitbench 8 | 9 | ## Status 10 | 11 | This was a quick 1-day proof-of-concept but quickly got refined to a stable product. 12 | [Comments](/zuckschwerdt/bitbench/issues) and [Code](/zuckschwerdt/bitbench/pulls) very much welcome. 13 | 14 | ## Development 15 | 16 | - Project setup 17 | `npm install` 18 | 19 | - Compiles and hot-reloads for development 20 | `npm run dev` 21 | 22 | - Compiles and minifies for production 23 | `npm run build` 24 | 25 | - Lints and fixes files 26 | `npm run lint` 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitbench", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "serve": "vite preview", 9 | "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src" 10 | }, 11 | "dependencies": { 12 | "vue": "^3.4.0" 13 | }, 14 | "devDependencies": { 15 | "@vitejs/plugin-vue": "^5.0.0", 16 | "eslint": "^9.0.0", 17 | "eslint-plugin-vue": "^10.0.0", 18 | "vite": "^6.0.0" 19 | }, 20 | "eslintConfig": { 21 | "root": true, 22 | "env": { 23 | "es2021": true 24 | }, 25 | "extends": [ 26 | "plugin:vue/essential", 27 | "eslint:recommended" 28 | ], 29 | "rules": {} 30 | }, 31 | "browserslist": [ 32 | "> 1%", 33 | "last 2 versions", 34 | "not dead", 35 | "not ie 11" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Christian W. Zuckschwerdt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 28 | 29 | 85 | -------------------------------------------------------------------------------- /src/components/BitBox.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 76 | -------------------------------------------------------------------------------- /src/bitstring.js: -------------------------------------------------------------------------------- 1 | // Parse and reformat bit strings 2 | 3 | function hexToBits(hexChar) { 4 | var n = parseInt(hexChar, 16) 5 | return [n >> 3 & 1, n >> 2 & 1, n >> 1 & 1, n >> 0 & 1] 6 | } 7 | 8 | function octToBits(octChar) { 9 | var n = parseInt(octChar, 8) 10 | return [n >> 2 & 1, n >> 1 & 1, n >> 0 & 1] 11 | } 12 | 13 | function terToBits(terChar) { 14 | terChar = terChar.replace(/Z/g, '2').replace(/X/g, '3') 15 | var n = parseInt(terChar, 4) 16 | return [n >> 1 & 1, n >> 0 & 1] 17 | } 18 | 19 | function decToBits(decChar) { 20 | var n = parseInt(decChar, 10) 21 | // coerce to unsigned 22 | return (n >>> 0).toString(2).split('').map((b) => b == '0' ? 0 : 1) 23 | } 24 | 25 | function trimBitsRight(bits, size) { 26 | var len = bits.length 27 | bits.length = size 28 | if (size > len) 29 | bits.fill(0, len - size) 30 | } 31 | 32 | function trimBitsLeft(bits, size) { 33 | while (bits.length > size) 34 | bits.shift() 35 | while (bits.length < size) 36 | bits.unshift(0) 37 | } 38 | 39 | function shiftBits(bits, size = 1, reverse = false, reverseBytes = false, invert = false, zeroFill = false) { 40 | var b = bits.slice(0, size) 41 | const truncated = (b.length != size) 42 | let classes = truncated ? ' truncated' : '' 43 | if (truncated && zeroFill) { 44 | trimBitsRight(b, size) 45 | classes = ' zerofill' 46 | } 47 | if (reverse) 48 | b = b.reverse() 49 | if (reverseBytes) 50 | b = Array.prototype.concat.apply([], b.reduce((acc, cur, i) => { 51 | if (!acc[i>>3]) 52 | acc[i>>3] = [] 53 | acc[i>>3].push(cur) 54 | return acc 55 | }, []).reverse()) 56 | if (invert) 57 | for (var i = 0; i < size; ++i) 58 | b[i] = !b[i] 59 | for (; size > 0; --size) 60 | bits.shift() 61 | 62 | b.truncated = truncated 63 | b.classes = classes 64 | b.zeroFill = truncated && zeroFill 65 | 66 | return b 67 | } 68 | 69 | // Shifts a number out of bits. 70 | // Requesting more than 52 bit returns a BigInt. 71 | // Signed (2's complement) is only available up 32 bits. 72 | // Note: using multiplication by 2 instead of left-shift which is limited to signed 32 bit 73 | function shiftNum(bits, size = 0, signed = false) { 74 | const width = Math.min(size || bits.length, bits.length) 75 | if (width > 52) { 76 | // maximum safe integer primitive is 52 bits, use BigInt for wider numbers 77 | let num = BigInt(0) 78 | for (let i = 0; i < width; i +=1) { 79 | num = (num * BigInt(2)) + BigInt(bits.shift()) 80 | } 81 | return num 82 | 83 | } else { 84 | let num = 0 85 | for (let i = 0; i < width; i +=1) { 86 | num = (num * 2) + bits.shift() 87 | } 88 | if (signed && width <= 32) { 89 | const shift_amount = 32 - width 90 | num = (num << shift_amount) >> shift_amount 91 | } 92 | return num 93 | } 94 | } 95 | 96 | function formatBitsBin(bits) { 97 | return bits 98 | .map((bit) => bit ? '1' : '0') 99 | .join('') 100 | } 101 | 102 | function formatBitsPop(bits, width = 1) { 103 | return chunkRight(bits, width) 104 | .map((b) => formatNumHeat(b.reduce((acc, cur) => acc + cur), width)) 105 | .join('') 106 | } 107 | 108 | function formatBitsValue(bits, width = 1) { 109 | return chunkRight(bits, width) 110 | .map((b) => formatNumHeat(parseInt(b.join(''), 2), 2**width - 1)) 111 | .join('') 112 | } 113 | 114 | function formatNumHeat(num, maxNum = 1) { 115 | num = ~~(num * 24 / maxNum); 116 | return `` 117 | } 118 | 119 | // break every chunkSize elements, right align (the first chunk may have less elements) 120 | function chunkRight(ary, chunkSize = 8) { 121 | var chunks = [] 122 | var len = ary.length 123 | var rem = len % chunkSize 124 | if (rem) 125 | chunks.push(ary.slice(0, rem)) 126 | for (var off = rem; off < len; off += chunkSize) { 127 | chunks.push(ary.slice(off, off + chunkSize)) 128 | } 129 | return chunks 130 | } 131 | 132 | // format 32 or 64 bits, to float 133 | function formatBitsFloat(bits) { 134 | const width = bits.length 135 | if (width != 32 && width != 64) { 136 | return 'NaF' 137 | } 138 | const buf = new ArrayBuffer(8) 139 | const view = new DataView(buf) 140 | 141 | for (let i = 0; i < width / 8; i += 1) { 142 | const num = shiftNum(bits, 8) 143 | view.setUint8(i, num) 144 | } 145 | 146 | if (width == 32) { 147 | return view.getFloat32(0).toString() 148 | } else { 149 | return view.getFloat64(0).toString() 150 | } 151 | } 152 | 153 | // format all bits, right aligned, char by char if possible 154 | // signed (2's complement) is only available for base 10 format and only up 32 bits 155 | function formatBits(bits, base = 16, signed = false) { 156 | var width = Math.log2(base) 157 | if (Math.ceil(width) == width) { 158 | // integral bit width 159 | return chunkRight(bits, width).map((b) => formatBitsChar(b, base)).join('') 160 | } else { 161 | // hope for the best otherwise 162 | return formatBitsChar(bits, base, signed) 163 | } 164 | } 165 | 166 | // note: using multiplication by 2 instead of left-shift which is limited to signed 32 bit 167 | // signed (2's complement) is only available for base 10 format and only up 32 bits 168 | function formatBitsChar(bits, base = 16, signed = false) { 169 | const pad = Math.ceil(bits.length / Math.log2(base)) 170 | let num = shiftNum(bits, bits.length, signed) 171 | if (base == 256) { // special case ascii 172 | const inv = num >= 128 173 | num %= 128 174 | const ctrl = (num < 32 || num == 127) 175 | if (ctrl) 176 | num = (num + 64) % 128 177 | const cls = (ctrl ? 'ctrl' : '') + (inv ? ' inv' : '') 178 | return `${ctrl ? '^' : ''}${String.fromCharCode(num)}` 179 | } 180 | if (signed) { 181 | // pad with spaces and one extra char for the minus sign 182 | return num.toString(base).padStart(pad + 1, '\xa0') // Non-breaking space is char 0xa0 (160 dec) 183 | } 184 | return num.toString(base).padStart(pad, '0') 185 | } 186 | 187 | function trChars(text) { 188 | const tr = "·ᚠᚢᚦᚨᚱᚲᚺᚾᛁᛃᛋᛏᛒᛚᛗ" 189 | return text.split('').map((c) => tr[parseInt(c, 16)]).join('') 190 | } 191 | 192 | function strToComments(text) { 193 | var comments = text.match(/\[.+?\]/g) || [] 194 | return comments.join() 195 | } 196 | 197 | function arrCompare(a, b, begin = 0, end = -1) { 198 | for (var i = begin; i < end; i += 1) { 199 | if (a[i] < b[i]) 200 | return -1 201 | else if (a[i] > b[i]) 202 | return 1 203 | } 204 | return 0 205 | } 206 | 207 | export default class { 208 | constructor(arg) { 209 | if (typeof arg == 'string' || arg instanceof String) { 210 | this.code = arg 211 | this.error = false 212 | this.bits = this.strToBits(arg) 213 | this.comments = strToComments(arg) 214 | } else { 215 | this.code = arg.code 216 | this.error = arg.error 217 | this.bits = arg.bits.slice() 218 | this.comments = arg.comments 219 | } 220 | } 221 | 222 | copy() { 223 | var dup = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this)) 224 | dup.bits = dup.bits.slice() // deep copy 225 | return dup 226 | } 227 | 228 | // parser 229 | 230 | strToBits(text) { 231 | var bits = [] 232 | text = text.split('') 233 | var base = 16 // default: hex 234 | var size = 0 235 | while (text.length) { 236 | var c = text.shift() 237 | if (c == ' ' || c == '\t') { 238 | // skip 239 | } else if (c == '[') { 240 | // skip comment 241 | while (text.length && c != ']') 242 | c = text.shift() 243 | 244 | } else if (c == '0' && text[0] == 'x') { 245 | base = 16 // hexadecimal 246 | text.shift() 247 | } else if (c == '0' && text[0] == 'z') { 248 | base = 10 // decimal 249 | text.shift() 250 | } else if (c == '0' && text[0] == 'o') { 251 | base = 8 // octal 252 | text.shift() 253 | } else if (c == '0' && text[0] == 't') { 254 | base = 4 // tristate (2-bit: 0,1,Z,X) 255 | text.shift() 256 | } else if (c == '0' && text[0] == 'y') { 257 | base = 2 // dual 258 | text.shift() 259 | 260 | } else if (c == 'x') { 261 | base = 16 // hexadecimal 262 | } else if (c == 'z') { 263 | base = 10 // decimal 264 | } else if (c == 'o') { 265 | base = 8 // octal 266 | } else if (c == 't') { 267 | base = 4 // tristate (2-bit: 0,1,Z,X) 268 | } else if (c == 'y') { 269 | base = 2 // dual 270 | 271 | } else if (c == '{') { 272 | if (size > 0) 273 | trimBitsRight(bits, size) 274 | size = '' 275 | while (text.length && text[0] != '}') 276 | size += text.shift() 277 | text.shift() // pop closing brace 278 | // overall target length after the bits are added 279 | size = bits.length + parseInt(size, 10) 280 | if (isNaN(size)) 281 | size = 0 282 | } else if (base == 16) { 283 | Array.prototype.push.apply(bits, hexToBits(c)) 284 | } else if (base == 8) { 285 | Array.prototype.push.apply(bits, octToBits(c)) 286 | } else if (base == 4) { 287 | Array.prototype.push.apply(bits, terToBits(c)) 288 | } else if (base == 10) { 289 | // special case, read the whole number in, and pad left 290 | while (text[0] >= '0' && text[0] <= '9') 291 | c += text.shift() 292 | var b = decToBits(c) 293 | if (size > 0) 294 | trimBitsLeft(b, size - bits.length) // just the field length 295 | size = 0 296 | Array.prototype.push.apply(bits, b) 297 | } else { 298 | bits.push(c == '0' ? 0 : 1) 299 | } 300 | } 301 | if (size > 0) 302 | trimBitsRight(bits, size) 303 | return bits 304 | } 305 | 306 | // simple ops 307 | 308 | invert(boolInvert=true) { 309 | var len = this.bits.length 310 | if (boolInvert) 311 | for (var i = 0; i < len; ++i) 312 | this.bits[i] = this.bits[i] ? 0 : 1 313 | return this 314 | } 315 | 316 | xor(xorText = '') { 317 | if (xorText) { 318 | var xbits = this.strToBits(xorText) 319 | var xlen = xbits.length 320 | 321 | // hidden mode: if mask is all 0 then take mask from start of data 322 | var n = 0 323 | for (var j = 0; j < xlen; ++j) { 324 | n = n * 2 + xbits[j] 325 | } 326 | if (n == 0) 327 | xbits = this.bits.slice(0, xbits.length) 328 | 329 | var len = this.bits.length 330 | for (var i = 0; i < len; ++i) 331 | this.bits[i] ^= xbits[i % xlen] 332 | } 333 | return this 334 | } 335 | 336 | reflect(boolReflect = true) { 337 | var len = this.bits.length 338 | if (boolReflect) 339 | for (var i = 0; i < len; i += 8) { 340 | var byte = this.bits.slice(i, i + 8) 341 | this.bits[i + 0] = byte[7] || 0 342 | this.bits[i + 1] = byte[6] || 0 343 | this.bits[i + 2] = byte[5] || 0 344 | this.bits[i + 3] = byte[4] || 0 345 | this.bits[i + 4] = byte[3] || 0 346 | this.bits[i + 5] = byte[2] || 0 347 | this.bits[i + 6] = byte[1] || 0 348 | this.bits[i + 7] = byte[0] || 0 349 | } 350 | return this 351 | } 352 | 353 | shiftLeft(shiftAmount=1) { 354 | for (; shiftAmount < 0; ++shiftAmount) 355 | this.bits.unshift(0) 356 | for (; shiftAmount > 0; --shiftAmount) 357 | this.bits.shift() 358 | return this 359 | } 360 | 361 | shiftRight(shiftAmount=1) { 362 | for (; shiftAmount < 0; ++shiftAmount) 363 | this.bits.shift() 364 | for (; shiftAmount > 0; --shiftAmount) 365 | this.bits.unshift(0) 366 | return this 367 | } 368 | 369 | padLeft(padAmount = 1) { 370 | for (; padAmount < 0; ++padAmount) 371 | this.bits.shift() 372 | for (; padAmount > 0; --padAmount) 373 | this.bits.unshift(0) 374 | return this 375 | } 376 | 377 | padRight(padAmount = 1) { 378 | for (; padAmount < 0; ++padAmount) 379 | this.bits.pop() 380 | for (; padAmount > 0; --padAmount) 381 | this.bits.push(0) 382 | return this 383 | } 384 | 385 | // summary functions 386 | 387 | sumAdd(offset = 0, length = 0, width = 4) { 388 | if (width <= 0) 389 | return 0 390 | if (offset < 0) 391 | offset = this.bits.length + offset 392 | if (length <= 0) 393 | length = this.bits.length + length 394 | 395 | var sum = 0 396 | for (var i = offset; i < offset + length - width + 1;) { 397 | var end = i + width 398 | var n = 0 399 | for (; i < end; ++i) { 400 | n = n * 2 + this.bits[i] 401 | } 402 | sum += n 403 | } 404 | return sum 405 | } 406 | 407 | sumXor(offset = 0, length = 0, width = 4) { 408 | if (width <= 0) 409 | return 0 410 | if (offset < 0) 411 | offset = this.bits.length + offset 412 | if (length <= 0) 413 | length = this.bits.length + length 414 | 415 | var sum = 0 416 | for (var i = offset; i < offset + length - width + 1;) { 417 | var end = i + width 418 | var n = 0 419 | for (; i < end; ++i) { 420 | n = n * 2 + this.bits[i] 421 | } 422 | sum ^= n 423 | } 424 | return sum 425 | } 426 | 427 | // transform ops 428 | 429 | matchPreamble(match) { 430 | if (match && match.bits.length > 0) { 431 | var matchLen = match.bits.length 432 | while (this.bits.length > 0 && arrCompare(this.bits, match.bits, 0, matchLen)) 433 | this.bits.shift() 434 | for (var i = match.bits.length; this.bits.length > 0 && i > 0; i -= 1) 435 | this.bits.shift() 436 | } 437 | return this 438 | } 439 | 440 | matchSync(match) { 441 | if (match && match.bits.length > 0) { 442 | var matchLen = match.bits.length 443 | while (this.bits.length > 0 && arrCompare(this.bits, match.bits, 0, matchLen)) 444 | this.bits.shift() 445 | } 446 | return this 447 | } 448 | 449 | decodeMC() { 450 | var ret = [] 451 | for (var i = 0; i + 1 < this.bits.length; i += 2) { 452 | if (this.bits[i] > this.bits[i + 1]) 453 | ret.push(1) 454 | else if (this.bits[i] < this.bits[i + 1]) 455 | ret.push(0) 456 | else { 457 | this.error += 1 458 | break 459 | } 460 | } 461 | this.bits = ret 462 | return this 463 | } 464 | 465 | decodeMCI() { 466 | var ret = [] 467 | for (var i = 0; i + 1 < this.bits.length; i += 2) { 468 | if (this.bits[i] < this.bits[i + 1]) 469 | ret.push(1) 470 | else if (this.bits[i] > this.bits[i + 1]) 471 | ret.push(0) 472 | else { 473 | this.error += 1 474 | break 475 | } 476 | } 477 | this.bits = ret 478 | return this 479 | } 480 | 481 | decodeDMC() { 482 | var ret = [] 483 | for (var i = 0; i + 1 < this.bits.length; i += 2) { 484 | if (this.bits[i] == this.bits[i + 1]) 485 | ret.push(1) 486 | else 487 | ret.push(0) 488 | if (i + 1 < this.bits.length && this.bits[i + 1] == this.bits[i + 2]) { 489 | this.error += 1 490 | break 491 | } 492 | } 493 | this.bits = ret 494 | return this 495 | } 496 | 497 | // output 498 | 499 | toHex() { 500 | return this.toFormat('8h ') 501 | } 502 | 503 | toFormat(fmt, options = {}) { 504 | const zeroFill = options.zeroFill 505 | var out = '' 506 | var bits = this.bits.slice() 507 | var fmts = fmt.split('') 508 | var reverse = false 509 | var reverseBytes = false 510 | var invert = false 511 | var consumed = false 512 | while (bits.length) { 513 | if (!fmts.length) 514 | if (consumed) 515 | fmts = fmt.split('') 516 | else 517 | break 518 | 519 | // pop a number if available 520 | var size = '' 521 | while (fmts[0] >= '0' && fmts[0] <= '9') 522 | size += fmts.shift() 523 | size = parseInt(size, 10) 524 | if (isNaN(size)) 525 | size = 0 526 | 527 | // get flags or apply a format 528 | var f = fmts.shift() 529 | if (f == '~') { 530 | invert = !invert 531 | } else if (f == '^') { 532 | reverse = !reverse 533 | } else if (f == '>') { 534 | reverseBytes = false 535 | } else if (f == '<') { 536 | reverseBytes = true 537 | } else if (f == 'b') { 538 | if (!size) 539 | size = 1 540 | out += formatBitsBin(shiftBits(bits, size, reverse, reverseBytes, invert)) 541 | reverse = false 542 | reverseBytes = false 543 | invert = false 544 | consumed = true 545 | } else if (f == 'p') { // population count as heatmap 546 | if (!size) 547 | size = 1 548 | out += formatBitsPop(shiftBits(bits, size, reverse, reverseBytes, invert), size) 549 | reverse = false 550 | reverseBytes = false 551 | invert = false 552 | consumed = true 553 | } else if (f == 'v') { // value as heatmap 554 | if (!size) 555 | size = 1 556 | out += formatBitsValue(shiftBits(bits, size, reverse, reverseBytes, invert), size) 557 | reverse = false 558 | reverseBytes = false 559 | invert = false 560 | consumed = true 561 | } else if (f == 'h') { 562 | if (!size) 563 | size = 4 564 | const b = shiftBits(bits, size, reverse, reverseBytes, invert, zeroFill) 565 | out += '' + formatBits(b, 16) + '' 566 | reverse = false 567 | reverseBytes = false 568 | invert = false 569 | consumed = true 570 | } else if (f == 'd') { 571 | if (!size) 572 | size = 8 573 | const b = shiftBits(bits, size, reverse, reverseBytes, invert, zeroFill) 574 | out += '' + formatBits(b, 10, false) + '' 575 | reverse = false 576 | reverseBytes = false 577 | invert = false 578 | consumed = true 579 | } else if (f == 's') { 580 | if (!size) 581 | size = 8 582 | const b = shiftBits(bits, size, reverse, reverseBytes, invert, zeroFill) 583 | out += '' + formatBits(b, 10, true) + '' 584 | reverse = false 585 | reverseBytes = false 586 | invert = false 587 | consumed = true 588 | } else if (f == 'f') { 589 | if (!size) 590 | size = 32 591 | const b = shiftBits(bits, size, reverse, reverseBytes, invert, zeroFill) 592 | out += '' + formatBitsFloat(b) + '' 593 | reverse = false 594 | reverseBytes = false 595 | invert = false 596 | consumed = true 597 | } else if (f == 'c') { 598 | if (!size) 599 | size = 8 600 | const b = shiftBits(bits, size, reverse, reverseBytes, invert, zeroFill) 601 | out += '' + formatBits(b, 256) + '' 602 | reverse = false 603 | reverseBytes = false 604 | invert = false 605 | consumed = true 606 | } else if (f == 'r') { 607 | if (!size) 608 | size = 4 609 | const b = shiftBits(bits, size, reverse, reverseBytes, invert, zeroFill) 610 | out += '' + trChars(formatBits(b, 16)) + '' 611 | reverse = false 612 | reverseBytes = false 613 | invert = false 614 | consumed = true 615 | } else if (f == 'x') { 616 | if (!size) 617 | size = 1 618 | shiftBits(bits, size) 619 | reverse = false 620 | invert = false 621 | consumed = true 622 | } else { 623 | // or render plain char 624 | out += f 625 | } 626 | } 627 | return out 628 | } 629 | } 630 | -------------------------------------------------------------------------------- /src/components/BitBench.vue: -------------------------------------------------------------------------------- 1 | 176 | 177 | 375 | 376 | 600 | --------------------------------------------------------------------------------