diff --git a/src/lib/Documentation/bitsandhexa.md b/src/lib/Documentation/bitsandhexa.md new file mode 100644 index 000000000..bad4709ce --- /dev/null +++ b/src/lib/Documentation/bitsandhexa.md @@ -0,0 +1,192 @@ +# Bitwise+ v1.3 +## Bitwise Operations for Decimals, Binary, and Hexadecimal +### By BurningHot687/Raichu-Model/-Rig + +If you are unfamiliar with bitwise operations, then hopefully this documentation can help you. If you still need further reading, you may go to this [Wikipedia Article](https://en.wikipedia.org/wiki/Bitwise_operation). I do not claim to be an expert, so these explanations might not be the best unless you've got the context for them. + +###### Keep in mind that version 1.3 currently only supports binary, decimal, hexadecimal, and octals. All outputs, unless specified otherwise, are going to be in decimal. All inputs, unless specified otherwise, are assumed decimal unless there is a hexadecimal character within it. Also keep in mind Scratch has a 32 bit system. + +--- +```scratch +> (3)::#15448f +``` +Signed right shift. Think of it like this: +We have a number -13 in binary: +`11111111111111111111111111110011` +The sign bit at the very left is `1`, and let's say we shift it 3 places to the right without accounting for the sign. +`00011111111111111111111111111110` +That's a completely different number! (`536870899`) +For this reason, for each shift, we "duplicate" the sign bit and move it over to the left. After three shifts we end up with `-2`. +`11111111111111111111111111111110` +Obviously positive numbers wouldn't be affected drastically due to their sign bits being `0`. +```scratch +([13] \<\< (3)::#15448f +``` +Shifts the bits left by the amount requested (`1111` to `111100` if the amount was `2`). +```scratch +([-13] >>> (3)::#15448f +``` +Unsigned right shift. Just shifts it to the right without caring about the sign bit: +`11111111111111111111111111110011` to `00011111111111111111111111111110` or `-13` to `536870899` +```scratch +([-13] ↻ (3)::#15448f +``` +Circular right shift: +Basically an unsigned right shift but instead of deleting bits they are looped to the 32nd bit. +```scratch +([-13] ↺ (3)::#15448f +``` +Same as before but opposite direction. + +--- +```scratch +(() & () | and::#15448f +``` +Bitwise and. + +```scratch +(() | () | or::#15448f +``` + +Bitwise or. + +```scratch +(() ^ () | xor::#15448f +``` + +Bitwise exclusive or (returns `1` if both bits are different). + +```scratch +(~() | not::#15448f +``` + +Bitwise not. + +```scratch +(~() & () | nand::#15448f +``` + +Bitwise nand (`0` if both inputs are on). + +```scratch +(~() | () | nor::#15448f +``` + +Bitwise nor (`1` if both inputs are off). + +```scratch +(~() ^ () | xnor::#15448f +``` + +Bitwise exclusive nor (`1` if both inputs are the same). + +## Extras + +These blocks are more experimental and definitely require updates here and there. These are meant to be used for specific-use cases. + +--- + +```scratch +(character (0) of [f] to [UTF-16 v] in [decimal v]::#15448f +``` + +Takes in a string and applies +```javascript +"string".charCodeAt(number); +``` + +`codePointAt` is used for Unicode. + +```scratch +(number (41) using [UTF-16 v] in [decimal v] to character::#15448f +``` + +Takes in a number and applies +```javascript +String.fromCharCode(number); +``` + +`fromCodePoint` is used for Unicode. + +```scratch +(::ring)[foo?!] to [UTF-16 v] array in [decimal v](::ring)::ring control :: #15448f +``` + +Takes in an array and turns it into a string. + +```scratch +([UTF-16 v] array ((::ring)(::ring):: ring control :: #0a094f) in [decimal v] to string::#15448f +``` + +Takes in an array and returns a string. + +--- + +```scratch +(0x ()::#15448f +``` + +Takes in a hexadecimal number and returns a decimal. + +```scratch +(0b ()::#15448f +``` + +Takes in a binary number and returns a decimal. + +```scratch +(0o ()::#15448f +``` + +Takes in an octal number and returns a decimal. + +```scratch +(convert float 32 (6.28) to [binary v]::#15448f +``` + +Takes in a single-precision float (32 bits) and turns it into the requested base. + +```scratch +(convert [f00] in [hexadecimal v] to float 32::#15448f +``` +Takes in a number, reads it in the assigned base, and converts it into a float32. Because of the way floats are stored, using the above block as the number input in this block would most likely result in a different number being outputted, with a few exceptions. + +```scratch +(reverse endianness of (37) in [decimal v]::#15448f +``` + +Switches the byte order of the provided number. + +--- + +These blocks probably won't work with extra blocks and *might* break normal blocks (or at least show unexpected behavior). + +```scratch +use a [static v] length for binary::#15448f +``` + +Changes the representation of binary numbers. Two's complement is applied to the most significant bit provided rather than the 32nd bit in dynamic mode. + +```scratch + 31 || IDX < 0) return ""; + let cValue = NUM; + if (!(isItDecimal(cValue) || isItHexadecimal(cValue))) return ""; + if (isItHexadecimal(cValue) && /[abcdef]/i.test(cValue)) { + cValue = "0x" + cValue; + } + if (IDX > parseInt(cValue).toString(2).length && !fullLength) return ""; + return (parseInt(cValue) >>> IDX) & 1; + }; + + function binaryReformat(Value, neg = true) { + let computedValue = (Value >>> 0).toString(2); + let newValue = 0; + for (let i = 0; i < computedValue.length; i++) { + if (computedValue[i] == "0") break; + newValue++; + } + newValue--; + if (!fullLength) { + if (neg) computedValue = computedValue.slice(newValue); + if (!neg) computedValue = "0" + computedValue + } + return computedValue; + }; + + function clamp(value, min, max) { + return Math.max(min, Math.min(value, max)); + }; + + function binaryToDecimal(computedValue) { + let newerValue = 0; + for (let i = computedValue.length; i > 0; i--) { + newerValue += parseInt(computedValue[i - 1]) * (Math.pow(2, computedValue.length - i)) * ((i === 1) ? -1 : 1); + } + return newerValue; + }; + + function binaryStupidity(value) { + return fullLength ? value : binaryToDecimal(binaryReformat(value, binaryToDecimal(value.toString(2)) < 0)); + }; + + function leadingZeroez(computeValue) { + let returnValue = ''; + for (let i = 0; i < computeValue.length; i++) { + if (computeValue[i] != "0") break; + returnValue = returnValue.concat("0"); + } + return returnValue; + }; + + function chooseBaseValue(text) { + return basesArray.indexOf(text) === 0 ? 10 : basesArray.indexOf(text) === 1 ? 2 : basesArray.indexOf(text) === 2 ? 16 : 8; + }; + + class Extension { + constructor() { + if (extraFeaturesOn) if (!vm.jwArray) vm.extensionManager.loadExtensionIdSync('jwArray'); jwArray = vm.jwArray; + } + + getInfo() { + const extBlockArray = [ + { + text: "Strings", + blockType: Scratch.BlockType.LABEL, + }, + { + opcode: "charToBit", + text: "character [NUM] of [CHAR] to [ENCODE] in [BASE]", + blockType: Scratch.BlockType.REPORTER, + arguments: { + NUM: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + CHAR: { + type: Scratch.ArgumentType.STRING, + defaultValue: "f", + }, + ENCODE: { + type: Scratch.ArgumentType.STRING, + menu: "ENCODING", + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES", + }, + }, + }, + { + opcode: "bitToChar", + text: "number [NUM] using [ENCODE] in [BASE] to character", + blockType: Scratch.BlockType.REPORTER, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "41", + }, + ENCODE: { + type: Scratch.ArgumentType.STRING, + menu: "ENCODING", + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES", + }, + }, + }, + ...extraFeaturesOn ? [{ + opcode: "stringToBitArray", + text: "[STR] to [ENCODE] array in [BASE]", + arguments: { + STR: { + type: Scratch.ArgumentType.STRING, + defaultValue: "foo?!", + }, + ENCODE: { + type: Scratch.ArgumentType.STRING, + menu: "ENCODING", + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES", + }, + }, + ...jwArray.Block + },] : [], + ...extraFeaturesOn ? [{ + opcode: "bitArrayToString", + text: "[ENCODE] array [ARRAY] in [BASE] to string", + blockType: Scratch.BlockType.REPORTER, + arguments: { + ARRAY: jwArray.Argument, + ENCODE: { + type: Scratch.ArgumentType.STRING, + menu: "ENCODING", + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES", + }, + }, + },] : [], + "---", + { + text: "Constants", + blockType: Scratch.BlockType.LABEL, + }, + { + opcode: 'largestInt', + text: 'largest positive integer', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + switches: [ 'smallestInt', 'largestUint', 'largestPosFloat', 'smallestPosFloat', 'smallestNegativeFloat', 'largestNegativeFloat' ], + }, + { + opcode: 'smallestInt', + text: 'smallest negative integer', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + switches: [ 'largestInt', 'largestUint', 'largestPosFloat', 'smallestPosFloat', 'smallestNegativeFloat', 'largestNegativeFloat' ], + }, + { + opcode: 'largestUint', + text: 'largest unsigned integer', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + switches: [ 'largestInt', 'smallestInt', 'largestPosFloat', 'smallestPosFloat', 'smallestNegativeFloat', 'largestNegativeFloat' ], + }, + { + opcode: 'largestPosFloat', + text: 'largest positive float', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + switches: [ 'largestInt', 'smallestInt', 'largestUint', 'smallestPosFloat', 'smallestNegativeFloat', 'largestNegativeFloat' ], + }, + { + opcode: 'smallestPosFloat', + text: 'smallest positive float', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + switches: [ 'largestInt', 'smallestInt', 'largestUint', 'largestPosFloat', 'smallestNegativeFloat', 'largestNegativeFloat' ], + }, + { + opcode: 'smallestNegativeFloat', + text: 'smallest negative float', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + switches: [ 'largestInt', 'smallestInt', 'largestUint', 'largestPosFloat', 'smallestPosFloat', 'largestNegativeFloat' ], + }, + { + opcode: 'largestNegativeFloat', + text: 'largest negative float', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + switches: [ 'largestInt', 'smallestInt', 'largestUint', 'largestPosFloat', 'smallestPosFloat', 'smallestNegativeFloat' ], + }, + '---', + { + text: "Utilities", + blockType: Scratch.BlockType.LABEL, + }, + { + opcode: "hexaNum", + text: "Ox[NUM]", + switchText: "Ox", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: '0', + }, + }, + switches: [ 'bitNum', 'octNum' ], + }, + { + opcode: "bitNum", + text: "Ob[NUM]", + switchText: "Ob", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.NUMBER, + }, + }, + switches: [ 'hexaNum', 'octNum' ], + }, + { + opcode: "octNum", + text: "Oo[NUM]", + switchText: "Oo", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.NUMBER, + }, + }, + switches: [ 'hexaNum', 'bitNum' ], + }, + { + opcode: 'convertSingleToBases', + text: 'float32 [NUM] to [BASE]', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 6.28, + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES_NO_DEC", + }, + }, + }, + { + opcode: 'convertBasesToSingle', + text: '[NUM] in [BASE] to float32', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'f00', + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES", + }, + }, + }, + { + opcode: "convertToLittleEndian", + text: "reverse endianness of [NUM] in [BASE]", + tooltip: 'This just basically reverses the byte order. Doesn\'t support dynamic length.', + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "37", + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES", + }, + }, + }, + "---", + { + text: "Configuration Settings ⚠", + blockType: Scratch.BlockType.LABEL, + }, + { + text: "Likely to not work as intended!", + blockType: Scratch.BlockType.LABEL, + }, + { + opcode: "binaryLengthSetter", + text: "use a [LENGTH] length for binary", + blockType: Scratch.BlockType.COMMAND, + arguments: { + LENGTH: { + type: Scratch.ArgumentType.STRING, + menu: "LENGTHS", + } + }, + }, + { + opcode: "binaryLengthGetter", + text: "using [LENGTH] length?", + blockType: Scratch.BlockType.BOOLEAN, + label: selLengthIsFull ? "using static length" : "using dynamic length", + disableMonitor: true, // NEED TO FIX SOMEDAY + arguments: { + LENGTH: { + type: Scratch.ArgumentType.STRING, + menu: "LENGTHS", + }, + }, + }, + ]; + return { + id: "burninghot687bitwisewhexa", + name: Scratch.translate("Bitwise") + "+", + color1: "#15448f", + color2: "#0f1f70", + color3: "#0a094f", + menuIconURI: iconCircle, + blockIconURI: icon, + isDynamic: true, + + blocks: [ + { + opcode: "bitwiseDocumentationButton", + text: "Open Documentation", + blockType: Scratch.BlockType.BUTTON, + }, + { + opcode: "isNumActuallyBase", + text: "is [NUM] [BASE]?", + blockType: Scratch.BlockType.BOOLEAN, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "1011", + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES", + }, + }, + }, + { + opcode: "convertBaseTypesBitW", + text: "[NUM] from [FROM] to [BASE]", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + // allowDropAnywhere: true, could potentially save on blocks in minor use cases and doesn't harm otherwise? + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "4d2", + }, + FROM: { + type: Scratch.ArgumentType.STRING, + menu: "BASES2", + }, + BASE: { + type: Scratch.ArgumentType.STRING, + menu: "BASES", + }, + }, + }, + { + opcode: "getBitAtIdx", + text: "get bit at index [IDX] of [NUM]", + switchText: "get bit", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + allowDropAnywhere: true, + arguments: { + IDX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 3, + }, + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: '13', + }, + }, + switches: [ "getHexAtIdx", "getOctAtIdx" ], + }, + { + opcode: "getHexAtIdx", + text: "get hex at index [IDX] of [NUM]", + switchText: "get hex", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + allowDropAnywhere: true, + arguments: { + IDX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0, + }, + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: 'de5', + }, + }, + switches: [ "getBitAtIdx", "getOctAtIdx" ], + }, + { + opcode: "getOctAtIdx", + text: "get octal at index [IDX] of [NUM]", + switchText: "get octal", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + allowDropAnywhere: true, + arguments: { + IDX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1, + }, + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: '213', + }, + }, + switches: [ "getBitAtIdx", "getHexAtIdx" ], + }, + "---", + { + text: "Bitwise Manipulation", + blockType: Scratch.BlockType.LABEL, + }, + { + opcode: "signedRightShiftBitz", + text: "[NUM] >> [AMOUNT]", + switchText: ">>", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "4d2", + }, + AMOUNT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 3, + } + }, + switches: [ "leftShiftBitz", "unsignedRightShiftBitz", "circularRightShiftBitz", "circularLeftShiftBitz" ], + }, + { + opcode: "leftShiftBitz", + text: "[NUM] << [AMOUNT]", + switchText: "<<", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "31", + }, + AMOUNT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2, + } + }, + switches: [ "signedRightShiftBitz", "unsignedRightShiftBitz", "circularRightShiftBitz", "circularLeftShiftBitz" ], + }, + { + opcode: "unsignedRightShiftBitz", + text: "[NUM] >>> [AMOUNT]", + switchText: ">>>", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "fe5", + }, + AMOUNT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, + } + }, + switches: [ "signedRightShiftBitz", "leftShiftBitz", "circularRightShiftBitz", "circularLeftShiftBitz" ], + }, + { + opcode: "circularRightShiftBitz", + text: "[NUM] ↻ [AMOUNT]", + switchText: "↻", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "fe5", + }, + AMOUNT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, + } + }, + switches: [ "signedRightShiftBitz", "leftShiftBitz", "unsignedRightShiftBitz", "circularLeftShiftBitz" ], + }, + { + opcode: "circularLeftShiftBitz", + text: "[NUM] ↺ [AMOUNT]", + switchText: "↺", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + defaultValue: "fe5", + }, + AMOUNT: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5, + } + }, + switches: [ "signedRightShiftBitz", "leftShiftBitz", "unsignedRightShiftBitz", "circularRightShiftBitz" ], + }, + '---', + { + text: "Bitwise Operators", + blockType: Scratch.BlockType.LABEL, + }, + { + opcode: "bitwiseAndOperator", + text: "[NUM] & [NUM2] | and", + switchText: "& and", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + } + }, + switches: [ 'bitwiseOrOperator', 'bitwiseXorOperator', 'bitwiseNotOperator', 'bitwiseNandOperator', 'bitwiseNorOperator', 'bitwiseXnorOperator' ], + }, + { + opcode: "bitwiseOrOperator", + text: "[NUM] | [NUM2] | or", + switchText: "| or", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + } + }, + switches: [ 'bitwiseAndOperator', 'bitwiseXorOperator', 'bitwiseNotOperator', 'bitwiseNandOperator', 'bitwiseNorOperator', 'bitwiseXnorOperator' ], + }, + { + opcode: "bitwiseXorOperator", + text: "[NUM] ^ [NUM2] | xor", + switchText: "^ xor", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + } + }, + switches: [ 'bitwiseOrOperator', 'bitwiseAndOperator', 'bitwiseNotOperator', 'bitwiseNandOperator', 'bitwiseNorOperator', 'bitwiseXnorOperator' ], + }, + { + opcode: "bitwiseNotOperator", + text: "~[NUM] | not", + switchText: "~ not", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + }, + }, + switches: [ 'bitwiseOrOperator', 'bitwiseXorOperator', 'bitwiseAndOperator', 'bitwiseNandOperator', 'bitwiseNorOperator', 'bitwiseXnorOperator' ], + }, + "---", + { + opcode: "bitwiseNandOperator", + text: "~[NUM] & [NUM2] | nand", + switchText: "~& nand", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + } + }, + switches: [ 'bitwiseOrOperator', 'bitwiseXorOperator', 'bitwiseNotOperator', 'bitwiseAndOperator', 'bitwiseNorOperator', 'bitwiseXnorOperator' ], + }, + { + opcode: "bitwiseNorOperator", + text: "~[NUM] | [NUM2] | nor", + switchText: "~| nor", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + } + }, + switches: [ 'bitwiseOrOperator', 'bitwiseXorOperator', 'bitwiseNotOperator', 'bitwiseNandOperator', 'bitwiseAndOperator', 'bitwiseXnorOperator' ], + }, + { + opcode: "bitwiseXnorOperator", + text: "~[NUM] ^ [NUM2] | xnor", + switchText: "~^ xnor", + blockType: Scratch.BlockType.REPORTER, + disableMonitor: true, + arguments: { + NUM: { + type: Scratch.ArgumentType.STRING, + }, + NUM2: { + type: Scratch.ArgumentType.STRING, + } + }, + switches: [ 'bitwiseOrOperator', 'bitwiseXorOperator', 'bitwiseNotOperator', 'bitwiseNandOperator', 'bitwiseNorOperator', 'bitwiseAndOperator' ], + }, + "---", + { + func: "openExtraBitwise", + text: extOpen ? "Close Extras" : "Open Extras", + blockType: Scratch.BlockType.BUTTON, + }, + ].concat(extOpen ? extBlockArray : []), + menus: { + BASES: { + acceptReporters: false, + items: basesArray.slice(), + }, + LENGTHS: { + acceptReporters: false, + items: ['static', 'dynamic'], + }, + BASES2: { + acceptReporters: false, + items: basesArray.slice(), + }, + ENCODING: { + acceptReporters: false, + items: ['UTF-16', 'Unicode'], + }, + BASES_NO_DEC: { + acceptReporters: false, + items: basesArray.slice(1), + }, + }, + }; + } + + openExtraBitwise() { + extOpen = !extOpen; + Scratch.vm.runtime.requestToolboxExtensionsUpdate(); + } + + bitwiseDocumentationButton() { + window.open("https://extensions.penguinmod.com/docs/bitsandhexa"); + } + + binaryLengthGetter(args) { + // Still need to fix monitors here lol + switch (args.LENGTH) { + case 'static': + selLengthIsFull = true; + return fullLength; + case 'dynamic': + selLengthIsFull = false; + return !fullLength; + } + // Scratch.vm.runtime.requestToolboxExtensionsUpdate(); + } + + binaryLengthSetter(args) { + switch (args.LENGTH) { + case 'static': + fullLength = true; + break; + case 'dynamic': + fullLength = false; + break; + } + } + + isNumActuallyBase(args) { + let computeValue = args.NUM; + if (isInCorrectFormat(computeValue) === false) { + return false; + } + + return testForFormat(computeValue, args.BASE); + } + + convertBaseTypesBitW(args) { + let computeValue = args.NUM; + if (isInCorrectFormat(computeValue) === false) { + return ""; + } + if (!testForFormat(computeValue, args.FROM)) { + return ""; + } + if (args.FROM === args.BASE) { + return args.NUM; + } + + if (fullLength) { + computeValue = parseInt(computeValue, chooseBaseValue(args.FROM)); + } else { + switch (basesArray.indexOf(args.FROM)) { + case 0: + computeValue = parseInt(computeValue); + break; + case 1: + computeValue = binaryToDecimal(computeValue); + break; + case 2: + computeValue = binaryToDecimal(leadingZeroez(computeValue) + (parseInt(computeValue, 16) >>> 0).toString(2)); + break; + case 3: + computeValue = binaryToDecimal(leadingZeroez(computeValue) + (parseInt(computeValue, 8) >>> 0).toString(2)); + break; + } + } + if (fullLength) computeValue = computeValue >> 0; + + let negative = computeValue < 0; + switch (basesArray.indexOf(args.BASE)) { + case 0: + computeValue = computeValue.toString(10); + break; + case 1: + computeValue = binaryReformat(computeValue, computeValue < 0); + break; + case 2: + computeValue = parseInt(binaryReformat(computeValue, negative), 2).toString(16); + if (!fullLength && !negative) computeValue = "0" + computeValue; + break; + case 3: + computeValue = parseInt(binaryReformat(computeValue, negative), 2).toString(8); + if (!fullLength && !negative) computeValue = "0" + computeValue; + break; + default: + return ""; + } + + return computeValue; + } + + getBitAtIdx(args) { + return getBitAt(args.NUM, args.IDX); + } + + getHexAtIdx(args) { + if (args.IDX > 7 || args.IDX < 0) return ""; + let cValue = args.NUM; + if (!(isItDecimal(cValue) || isItHexadecimal(cValue))) return ""; + if (isItHexadecimal(cValue) && /[abcdef]/i.test(cValue)) { + cValue = "0x" + cValue; + } + if (args.IDX > parseInt(cValue).toString(16).length && !fullLength) return ""; + return ((parseInt(cValue) >>> args.IDX * 4) & 15).toString(16); + } + + getOctAtIdx(args) { + if (args.IDX > 10 || args.IDX < 0) return ""; + let cValue = args.NUM; + if (!(isItDecimal(cValue) || isItHexadecimal(cValue))) return ""; + if (isItHexadecimal(cValue) && /[abcdef]/i.test(cValue)) { + cValue = "0x" + cValue; + } + if (args.IDX > parseInt(cValue).toString(8).length && !fullLength) return ""; + return ((parseInt(cValue) >>> args.IDX * 3) & 7).toString(8); + } + + signedRightShiftBitz(args) { + let computeValue = args.NUM; + if (!(isItDecimal(computeValue) || isItHexadecimal(computeValue))) return ""; + if (isItHexadecimal(computeValue) && /[abcdef]/i.test(computeValue)) { + computeValue = "0x" + computeValue; + } + + if (fullLength) { + return computeValue >> args.AMOUNT; + } + computeValue = leadingZeroez(computeValue) + (computeValue >> args.AMOUNT).toString(2); + let signBit = computeValue[0]; + return binaryToDecimal(signBit.repeat(args.AMOUNT) + computeValue); + } + + leftShiftBitz(args) { + let computeValue = args.NUM; + if (!(isItDecimal(computeValue) || isItHexadecimal(computeValue))) return ""; + if (isItHexadecimal(computeValue) && /[abcdef]/i.test(computeValue)) { + computeValue = "0x" + computeValue; + } + + if (fullLength) return computeValue << args.AMOUNT; + return binaryToDecimal(leadingZeroez(computeValue) + (computeValue << args.AMOUNT).toString(2)); + } + + unsignedRightShiftBitz(args) { + let computeValue = args.NUM; + if (!(isItDecimal(computeValue) || isItHexadecimal(computeValue))) return ""; + if (isItHexadecimal(computeValue) && /[abcdef]/i.test(computeValue)) { + computeValue = "0x" + computeValue; + } + + return binaryStupidity(computeValue >>> args.AMOUNT); + } + + circularRightShiftBitz(args) { + let computeValue = args.NUM; + if (!(isItDecimal(computeValue) || isItHexadecimal(computeValue))) return ""; + if (isItHexadecimal(computeValue) && /[abcdef]/i.test(computeValue)) { + computeValue = "0x" + computeValue; + } + + return binaryStupidity(computeValue >> args.AMOUNT | computeValue << (fullLength ? 32 : binaryReformat(computeValue) - args.AMOUNT)); + } + + circularLeftShiftBitz(args) { + let computeValue = args.NUM; + if (!(isItDecimal(computeValue) || isItHexadecimal(computeValue))) return ""; + if (isItHexadecimal(computeValue) && /[abcdef]/i.test(computeValue)) { + computeValue = "0x" + computeValue; + } + + return binaryStupidity(computeValue << args.AMOUNT | computeValue >> (fullLength ? 32 : binaryReformat(computeValue) - args.AMOUNT)); + } + + bitwiseAndOperator(args) { + let value1 = args.NUM; + let value2 = args.NUM2; + if (!(isItDecimal(value1) || isItHexadecimal(value2))) return ""; + if (!(isItDecimal(value2) || isItHexadecimal(value2))) return ""; + if (isItHexadecimal(value1) && /[abcdef]/i.test(value1)) { + value1 = "0x" + value1; + } + if (isItHexadecimal(value2) && /[abcdef]/i.test(value2)) { + value2 = "0x" + value2; + } + if (isNaN(parseInt(value1)) || isNaN(parseInt(value2))) { + return ""; + } + + return binaryStupidity(value1 & value2); + } + + bitwiseOrOperator(args) { + let value1 = args.NUM; + let value2 = args.NUM2; + if (!(isItDecimal(value1) || isItHexadecimal(value2))) return ""; + if (!(isItDecimal(value2) || isItHexadecimal(value2))) return ""; + if (isItHexadecimal(value1) && /[abcdef]/i.test(value1)) { + value1 = "0x" + value1; + } + if (isItHexadecimal(value2) && /[abcdef]/i.test(value2)) { + value2 = "0x" + value2; + } + if (isNaN(parseInt(value1)) || isNaN(parseInt(value2))) { + return ""; + } + + return binaryStupidity(value1 | value2); + } + + bitwiseXorOperator(args) { + let value1 = args.NUM; + let value2 = args.NUM2; + if (!(isItDecimal(value1) || isItHexadecimal(value2))) return ""; + if (!(isItDecimal(value2) || isItHexadecimal(value2))) return ""; + if (isItHexadecimal(value1) && /[abcdef]/i.test(value1)) { + value1 = "0x" + value1; + } + if (isItHexadecimal(value2) && /[abcdef]/i.test(value2)) { + value2 = "0x" + value2; + } + if (isNaN(parseInt(value1)) || isNaN(parseInt(value2))) { + return ""; + } + + return binaryStupidity(value1 ^ value2); + } + + bitwiseNotOperator(args) { + let value1 = args.NUM; + if (!(isItDecimal(value1) || isItHexadecimal(value2))) return ""; + if (isItHexadecimal(value1) && /[abcdef]/i.test(value1)) { + value1 = "0x" + value1; + } + if (isNaN(parseInt(value1))) { + return ""; + } + + return binaryStupidity(~value1); + } + + bitwiseNandOperator(args) { + let value1 = args.NUM; + let value2 = args.NUM2; + if (!(isItDecimal(value1) || isItHexadecimal(value2))) return ""; + if (!(isItDecimal(value2) || isItHexadecimal(value2))) return ""; + if (isItHexadecimal(value1) && /[abcdef]/i.test(value1)) { + value1 = "0x" + value1; + } + if (isItHexadecimal(value2) && /[abcdef]/i.test(value2)) { + value2 = "0x" + value2; + } + if (isNaN(parseInt(value1)) || isNaN(parseInt(value2))) { + return ""; + } + + return binaryStupidity(~(value1 & value2)); + } + + bitwiseNorOperator(args) { + let value1 = args.NUM; + let value2 = args.NUM2; + if (!(isItDecimal(value1) || isItHexadecimal(value2))) return ""; + if (!(isItDecimal(value2) || isItHexadecimal(value2))) return ""; + if (isItHexadecimal(value1) && /[abcdef]/i.test(value1)) { + value1 = "0x" + value1; + } + if (isItHexadecimal(value2) && /[abcdef]/i.test(value2)) { + value2 = "0x" + value2; + } + if (isNaN(parseInt(value1)) || isNaN(parseInt(value2))) { + return ""; + } + + return binaryStupidity(~(value1 | value2)); + } + + bitwiseXnorOperator(args) { + let value1 = args.NUM; + let value2 = args.NUM2; + if (!(isItDecimal(value1) || isItHexadecimal(value2))) return ""; + if (!(isItDecimal(value2) || isItHexadecimal(value2))) return ""; + if (isItHexadecimal(value1) && /[abcdef]/i.test(value1)) { + value1 = "0x" + value1; + } + if (isItHexadecimal(value2) && /[abcdef]/i.test(value2)) { + value2 = "0x" + value2; + } + if (isNaN(parseInt(value1)) || isNaN(parseInt(value2))) { + return ""; + } + + return binaryStupidity(~(value1 ^ value2)); + } + + hexaNum(args) { + return isItHexadecimal(args.NUM) ? parseInt(args.NUM, 16) : ''; + } + + bitNum(args) { + return isItBinary(args.NUM.toString()) ? parseInt(args.NUM.toString(), 2) : ''; + } + + octNum(args) { + return isItOctal(args.NUM.toString()) ? parseInt(args.NUM.toString(), 8) : ''; + } + + charToBit(args) { + if (args.ENCODE == 'UTF-16') return args.CHAR.charCodeAt(args.NUM).toString(chooseBaseValue(args.BASE)); + if (args.ENCODE == 'Unicode') return args.CHAR.codePointAt(args.NUM).toString(chooseBaseValue(args.BASE)); + } + + bitToChar(args) { + if (args.ENCODE == 'UTF-16') return String.fromCharCode(parseInt(args.NUM, chooseBaseValue(args.BASE))); + if (args.ENCODE == 'Unicode') return String.fromCodePoint(parseInt(args.NUM, chooseBaseValue(args.BASE))); + } + + stringToBitArray(args) { + let computeValue = []; + for (let i = 0; i < args.STR.length; i++) { + if (args.ENCODE == 'UTF-16') computeValue.push(args.STR.charCodeAt(i).toString(chooseBaseValue(args.BASE))); + if (args.ENCODE == 'Unicode') computeValue.push(args.STR.codePointAt(i).toString(chooseBaseValue(args.BASE))); + } + return new jwArray.Type(computeValue); + } + + bitArrayToString(args) { + let myArray = jwArray.Type.toArray(args.ARRAY).array; + if (myArray.length === 0) return ''; + let computeValue = ''; + for (let i = 0; i < myArray.length; i++) { + let charValue = parseInt(myArray[i], chooseBaseValue(args.BASE)); + computeValue = computeValue.concat(args.ENCODE === 'UTF-16' ? String.fromCharCode(charValue) : String.fromCodePoint(charValue)); + } + return computeValue; + } + + + convertToLittleEndian(args) { + let computeValue = parseInt(args.NUM, chooseBaseValue(args.BASE)); + computeValue = new Int32Array([computeValue]); + computeValue.reverse(); + const myDataView = new DataView(computeValue.buffer); + return myDataView.getInt32(0, false); + } + + convertSingleToBases(args) { + // https://stackoverflow.com/questions/25942516/double-to-byte-array-conversion-in-javascript is where I found this solution + // If I don't keep snoozing this Copilot I get jumpscared by it being smarter and faster than me 0_0' + let computeValue = parseFloat(args.NUM); + let buffer = new ArrayBuffer(4); + let intArray = new Int32Array(buffer); + let floatArray = new Float32Array(buffer); + floatArray[0] = computeValue; + + let binaryString = ''; + for (let i = floatArray.byteLength; i > 0; i--) { + let byte = (intArray[0] >> ((i - 1) * 8)) & 0xFF; + binaryString += byte.toString(chooseBaseValue(args.BASE)).padStart(basesArray.indexOf(args.BASE) == 1 ? 8 : basesArray.indexOf(args.BASE) == 2 ? 2 : 3, '0'); + } + + return binaryString; + } + + convertBasesToSingle(args) { + let computeValue = parseInt(args.NUM, chooseBaseValue(args.BASE)); + if (!testForFormat(computeValue, args.BASE)) { + return ""; + } + if ((computeValue >>> 0).toString(2).length > 32) return ''; + let myDataView = new DataView(new ArrayBuffer(4)); + myDataView.setInt32(0, computeValue, false); + return myDataView.getFloat32(0, false); + } + + largestInt() { + return 0x7fffffff >> 0; + } + + smallestInt() { + return 0x80000000 >> 0; + } + + largestUint() { + return 0xffffffff >>> 0; + } + + largestPosFloat() { + return 3.4028235e+38; + } + + smallestPosFloat() { + return 1.4012985e-45; + } + + smallestNegativeFloat() { + return -3.4028235e+38; + } + + largestNegativeFloat() { + return -1.4012985e-45; + } + } + Scratch.extensions.register(new Extension()); +})(Scratch); \ No newline at end of file diff --git a/static/images/BurningHot687/bitsandhexa.avif b/static/images/BurningHot687/bitsandhexa.avif new file mode 100644 index 000000000..e1ea4020a Binary files /dev/null and b/static/images/BurningHot687/bitsandhexa.avif differ