I'm looking for a lossless compression algorithm (like LZW or Huffman or anything) in javascript, that accepts and returns raw, binary data.
With 'binary data' I mean a sequence of bytes, which may come in any of the following forms:
a string containing characters with any value from 0 to 255
an array containing integers with any value from 0 to 255
a string containing a hexadecimal representation of the data (i.e. 2 hex digits per byte)
a string containing the base64 encoded representation of the data
or anything else that can be unambiguously converted from or to any of the above
Now obviously there are TONS of javascript implementations available everywhere, for a wide range of algorithms. However EVERYTHING I find seems to do crazy stuff like:
returning an array containing also values >255 (so what is the compression ratio now? how do I represent this in bytes, or how would I go about saving this to a file for example?)
messing with character encodings in strings, converting from/to unicode or url/html entities or whatnot (it's BINARY, character encoding does not apply here!)
return other representations that don't seem suitable for binary storage (i.e. cannot be converted to sequence of bytes)
Would anyone know of a good javascript compression (+decompression) implementation that suits my binary fetish?
I think I found what I was looking for after all: this deflate + inflate implementation in javascript seems to work with strings as byte sequences.
first of all create a closure for hold the binar or hex or decimal flags
function ASearch() { }
ASearch.Flag = {
Front_Wheel_Drive: 0xF, Rear_Wheel_Drive: 0xF0, Four_Wheel_Drive: 0xF00,
Auto: 0xFF, Manual: 0xFF00,
Gas: 0xF, Diesel: 0xF0, Hybrid: 0xF00, Electrical: 0xF000,
Two: 1, Three: 2, Four: 4, Five: 8, Six: 16, Eight: 32, Ten: 64, Twelve: 128
};
then set like this
SetFlag = (function (e) {
e = e.srcElement;
$("#" + e.parentNode.name).val(e.checked ?
$("#" + e.parentNode.name).val() | ASearch.Flag[e.id] :
$("#" + e.parentNode.name).val() ^ ASearch.Flag[e.id]);
});
this is an example for packed data in a 32 bit integer
there are four variable... i've used them for 18 flags.. this is fast and super effective
for example...
int i = 0; //binary = 0000 0000 0000 0000
i = i | 255; //binary = 0000 0000 1111 1111
i = i ^ 255; //binary = 0000 0000 0000 0000
i = i | 0xFF00; //binary = 1111 1111 0000 0000
i = i | 255; //binary = 1111 1111 1111 1111
i = i ^ 0xFF00; //binary = 0000 0000 1111 1111
Related
I want to generate UniqueID for objects, by generating the character part of the UniqueID from ASCII values, without declaring any Arrays, The Unique ID should start from AA01 and continue through AA99, then AB01 through AB99, then AC01 though AC99, AD01 -> AD99, -> AE01 -> AE99 ..and so on. I also need to apply padding, so the UniqueID always has 4 values like "AC08" instead of "AC8".
Below is a snippet of what I have done.
function genUID (a,b){
var res="";
var res2="";
var res3;
if (a=>65 && a<=90) {
res = String.fromCharCode(a);
if(b=>65 && b<=90) {
res2= String.fromCharCode(b); b++;
for(c=1;c<150;c++){
if(c<100){
(res3=c);
}
else {
(res3= c-99); }
console.log(res+""+res2+""+res3);
}
a++ }
} }
Are you not making this way more complicated than it needs to be? Just increase a normal number, format it to four digits length by padding zeroes on the left - and then just “translate” the first two numeric digits to their character “equivalent”, by adding the difference between the character codes for A and 0 ...
for(var i=1; i<3000; ++i) {
var padNum = ("000"+i).substr(-4),
uniqID =
String.fromCharCode(padNum.charCodeAt(0)+17) +
String.fromCharCode(padNum.charCodeAt(1)+17) +
padNum[2] +
padNum[3];
console.log(padNum, uniqID)
}
Result: (Snippet console here does not show the full result, but only the last few lines)
0001 AA01
0002 AA02
0003 AA03
0004 AA04
0005 AA05
0006 AA06
0007 AA07
0008 AA08
0009 AA09
0010 AA10
0011 AA11
...
0099 AA99
0100 AB00
0101 AB01
0102 AB02
...
0199 AB99
0200 AC00
0201 AC01
0202 AC02
...
0998 AJ98
0999 AJ99
1000 BA00
1001 BA01
1002 BA02
...
I have a weird requirement,
My destination only supports one integer, But I want to send two integers to it and later I want to get them back from a response.
for example,
allowed input:
{
'task': 2
}
I have subtask kind of a logic in my side, But my target is not aware of this. So, without letting know the target, can I somehow pack two integers and get decode them back in future?
Can this be achieved with hexadecimal?
You can combine any two numbers and get both numbers back using their product (a * b) as long as a * (a * b) + b < Number.MAX_SAFE_INTEGER
Here's a demo snippet:
(() => {
document.addEventListener("click", handleStuff);
// formula: c = (a * (a * b)) + b
// as long as c < 9007199254740991
const combine = (a, b) => ({
a: a,
b: b,
get c() { return this.a * this.b; },
get combined() { return this.a * this.c + this.b; },
get unraveled() { return [
Math.floor(this.combined / this.c),
this.combined % this.c ]; }
});
const log = txt => document.querySelector("pre").textContent = txt;
let numbers = combine(
+document.querySelector("#num1").value,
+document.querySelector("#num2").value );
function handleStuff(evt) {
if (evt.target.nodeName.toLowerCase() === "button") {
if (evt.target.id === "combine") {
numbers = combine(
+document.querySelector("#num1").value,
+document.querySelector("#num2").value );
if (numbers.combined > Number.MAX_SAFE_INTEGER) {
log (`${numbers.combined} too large, unraveled will be unreliable`);
} else {
log (`Combined ${numbers.a} and ${numbers.b} to ${numbers.combined}`);
}
} else {
log(`${numbers.combined} unraveled to ${numbers.unraveled}`);
}
}
}
})();
input[type=number] {width: 100px;}
<p>
<input type="number" id="num1"
value="12315" min="1"> first number
</p>
<p>
<input type="number" id="num2"
value="231091" min="1"> second number
</p>
<p>
<button id="combine">combine</button>
<button id="unravel">unravel</button>
</p>
<pre id="result"></pre>
Note: #RallFriedl inspired this answer
JSFiddle
Yes, you can, assuming your two integers don't contain more information than the one integer can handle.
Let's assume your tasks and sub tasks are in the range 1..255. Then you can encode
combined = (task * 256) + subtask
And decode
task = combined / 256
subtask = combined % 256
At first, you don't have to convert an integer to hexadecimal to do this. An integer is a value and decimal, hexadecimal or binary is a representation to visualize that value. So all you need is integer arithmetics to achieve your goal.
According to this answer the maximum allowed integer number in javascript would be 9007199254740991. If you write this down in binary you'll get 53 ones, which means there are 53 bits available to store within an integer. Now you can split up this into two or more smaller ranges as you need.
For example let's say you need to save three numbers, the first is always lower 4.294.967.296 (32-bit), the second always lower 65.536 (16-bit) and the third always lower 32 (5-bit). If you sum up all the bits of these three values, you'll get 53 bits which means it would perfectly match.
To pack all these values into one, all you need is to move them at the right bit position within the integer. In my example I'd like to let the 32 bit number on the lowest position, then the 16 bit number and at the highest position the 5 bit number:
var max32bitValue = 3832905829; // binary: 1110 0100 0111 0101 1000 0000 0110 0101
var max16bitValue = 47313; // binary: 1011 1000 1101 0001
var max5bitValue = 17; // binary: 1000 1
var packedValue = max32bitValue // Position is at bit 0, so no movement needed.
+ max16bitValue << 32 // Move it up next to the first number.
+ max5bitValue << 48; // Move it up next to the second number (32 + 16)
This single integer value can now be stored, cause is a perfectly valid javascript integer value, but for us it holds three values.
To get all three values out of the packed value, we have to pick the correct bits out of it. This involves two steps, first remove all unneeded bits on the lower side (by using shift right), then remove all unneeded bits on the higher side (by masking out):
var max32bitValueRead = packedValue & Math.pow(2, 32); // No bits on the lower side, just mask the higher ones;
var max16bitValueRead = (packedValue >> 32) & Math.pow(2, 16); // Remove first 32 bits and set all bits higher then 16 bits to zero;
var max5bitValueRead = (packedValue >> 48); // Remove first 48 bits (32 + 16). No higher bits there, so no mask needed.
So hope this helps to understand, how to put multiple integer values into one, if the ranges of these values don't exceed the maximum bit range. Depending on your needs you could put two values with 26 bits each into this or move the range like one 32 bit value and one 21 bit value or a 48 bit value and a 5 bit value. Just be sure what your maximum value for each one could be and set the width accordingly (maybe add one to three bits, just to be sure).
I wouldn't suggest using hexadecimal if you can not have 2 sequential numbers. Try converting to an ASCII character and then back. So if you wanted to send:
{ 'task': 21 }
You could set the 21 to a character like:
var a = 55; var b = String.fromCharCode(a); var send2 = { 'task': b };
And to convert it back it would be: var res = { 'task': b }; var original = res.task.charCodeAt();
I'm reading this explanation of DataView and there's an example there:
var littleEndian = (function() {
var buffer = new ArrayBuffer(2);
new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
// Int16Array uses the platform's endianness.
return new Int16Array(buffer)[0] === 256;
})();
I don't really understand what this line does:
new DataView(buffer).setInt16(0, 256, true /* littleEndian */);
Does it mean that the data stored in the range [0;256] bits should be stored in littleEndian?
Suppose we create an array buffer and array like this:
var dv = new DataView(new ArrayBuffer(4));
It means that we've got 32 bits in memory:
0000 0000 0000 0000 0000 0000 0000 0000
Now, we want to store the number 0x0103, which has the pattern:
0000 0001 0000 0011
Now, let's store this number in first two bytes using little endianess, and in the second two bytes using big endianess and see how it's laid out in the memory. So:
dv.setInt16(0, 0x0103, true);
dv.setInt16(2, 0x0103, false);
Now, the bits in the DataView have this pattern:
0000 0011 0000 0001 0000 0001 0000 0011
Here is the code to test that behavior:
var little = dv.getUint16(0);
little === 0x0103 // false
little === 0x0301 // true
var big = dv.getUint16(2);
big === 0x0103 // true
big === 0x0301 // false
I transmit a byte that's always less than 127 with a 1 bit flag to the client by ORing the byte with 0x80.
On the client side, in JavaScript, I have an Array() of numbers representing the bytes of the message (yes it's probably dumb but I haven't figured out typed arrays yet).
Everything works fine until I hit a number with the highest bit of the lowest byte set.
Number: 0011 0101
flag: 1000 0000
---------
1011 0101
Stored as
integer in ???
JavaScript
How can I retrieve the original byte (with the highest bit set to 0), plus the flag (denoted by the value of the highest bit)?
EXAMPLE:
(server)
byte x = 90
x | 0x80
> -38
(client - JavaScript)
var x = -38
x ^ 0x80
> -166
How do I get 90 back?
EDIT - I discovered this was due to another bug in my code... I wasn't going crazy with the encoding... sorry all...
Try the following in JavaScript:
var received = -38;
var adjusted = received & 0xFF; // 218
var original = adjusted ^ 0x80; // 90
That should solve your problem.
Explanation: All numbers in JavaScript stored in the double-precision floating point format:
Bitwise operators however can't deal with floating point numbers. Hence they convert their operands into 32-bit signed integers. [source]
-38 = 11111111 11111111 11111111 11011010
Hence if you do -38 ^ 0x80 you get the wrong answer as only the 8th bit from the right is set to 0. You need to first limit -38 to 8-bits before xoring it with 0x80. Only the least significant byte (i.e. 11011010) is needed. Hence we do -38 & 0xFF to get the least significant byte.
Now that you have the correct byte you may simply xor it with 0x80.
TLDR: Use byte & 0xFF ^ 0x80.
Not sure I understand the question, but I will give a shot: you have just to XORing the 0x80:
var received = 181; // 10110101
var num = received ^ 0x80;
console.log(num); // 53, 00110101
If you have a different result, probably there is something different in your code – if you run the code above, should give the expected result.
I'm not seeing a problem.
Here is some code I've written to test, with JSFiddle live demo
var val = 57;
var flag = 1;
var valWithFlag = val | (flag ? 0x80 : 0);
var newVal = (valWithFlag & 0x7F);
var newValFlag = (valWithFlag & 0x80 ? 1 : 0);
alert("Val: " + val.toString() + "\n" +
"Flag: " + flag.toString() + "\n" +
"Val With Flag: " + valWithFlag.toString() + "\n" +
"New Val Without Flag: " + newVal.toString() + "\n" +
"New Val Flag: " + newValFlag.toString() + "\n");
It is giving the desired results...
Val: 57
Flag: 1
Val With Flag: 185
New Val Without Flag: 57
New Val Flag: 1
UPDATE based on extra details provided by the OP
I think this is probably due to integers in javascript being held either as 32 or 64 bit values... so when you pass through -38 to javascript it isn't being held in the same way as the single byte on your server.
You need to convert that -38 into an 8-byte...
var val = -38;
var jsVal = (val & 0xFF);
Which should give you your 90 value to work with. Here is an updated JSFiddle
What does this JavaScript code mean?
flag &= ~CONST
Is it append, prepend, intersection or something else?
Look at Bitwise operators.
& Operator
& puts 1 where both operands' bits are 1.
Example
10000001 & 00000001 = 00000001
~ Operator
~ inverts the bits.
Example
~10000000 = 011111111;
flag &= ~CONST is short hand for flag = flag & ~CONST;.
You may have seen something similar, e.g. number *= 10.
This will turn off whatever constant represents.
For example, lets look at a hypothetical example of code which would represent the state of a window:
WS_HASBORDER = 0x01;
WS_HASCLOSEBUTTON = 0x02;
WS_HASMINIMIZEBUTTON = 0x04;
WS_HASMAXIMIZEBUTTON = 0x08;
WS_ISMAXIMIZED = 0x10;
We could represent the "state" of the window by using
windowState = WS_HASBORDER | WS_HASCLOSEBUTTON | ... etc
now, lets say we want to "turn off" one of these states, well, thats what your example code does...
windowState &= ~WS_HASBORDER
Now what the above code does, is it gets the compliment [i guess you could call it the inverted bits] of whatever is to its right, WS_HASBORDER.
So.. WS_HASBORDER has one bit turned on, and everything else is turned off. Its compliment has all bits turned on, except for the one bit that was turned off before.
Since I've represented the many constants as bytes, i'll just show you an example [not that javascript doesn't represent numbers as bytes, nor can you do so]
WS_HASBORDER = 0x01; //0000 0001
WS_HASCLOSEBUTTON = 0x02; //0000 0010
WS_HASMINIMIZEBUTTON = 0x04; //0000 0100
WS_HASMAXIMIZEBUTTON = 0x08; //0000 1000
WS_ISMAXIMIZED = 0x10; //0001 0000
_ now for an example
windowState = WS_HASBORDER | WS_HASCLOSEBUTTON | WS_HASMINIMIZEBUTTON |
WS_HASMAXIMIZEBUTTON | WS_ISMAXIMIZED;
0000 0001
0000 0010
0000 0100
0000 1000
and) 0001 0000
--------------
0001 1111 = 0x1F
So... windowState gets the value 0x1F
windowState &= ~ WS_HASMAXIMIZEBUTTON
WS_HASMAXIMIZEBUTTON: 0000 1000
~WS_HASMAXIMIZEBUTTON: 1111 0111
..To finish our calculation
windowState
&) ~WS_HASMAXIMIZEBUTTON
becomes
0001 1111
&) 1111 0111
-------------
0001 0111 = 0x07
Here are your resulting flags:
On:
WS_HASBORDER
WS_HASCLOSEBUTTON
WS_HASMINIMIZEBUTTON
WS_ISMAXIMIZED
Off:
WS_HASMAXIMIZEBUTTON
Hope that helps. Back to procrastinating homework I go! haha.