shaun
shaun

Reputation: 1273

node js Buffer Flip Binary Bits

I am working on some decoding in nodejs, and have a buffer:

59 19 F2 92  8C 88 88 88  89 88 EB 89  88 88 A1 8A 
88 88 88 88  89 88 A8 CD  88 88 88 DB  88 88 88 DC 
88 88 88 A5  88 88 88 BD  88 88 88 B2  88 88 88 B8 
88 88 88 B8  88 88 88 8A  88 89 89 8D  88 89 8D 8E 
88 89 89 8F  88 89 89 80  88 8C 87 88  88 88 81 88 
89 8B 82 88  8C 9C 88 88  88 85 88 8C  88 88 88 88 
87 88 89 8A  99 88 89 88  9B 88 8C 8D  88 88 88 9C 
88 8C 8D 88  88 88 9D 88  8C 8D 88 88  88 9E 88 8C 
A0 88 88 88  9F 88 94 DA  88 88 88 ED  88 88 88 FE 
88 88 88 ED  88 88 88 FA  88 88 88 FB  88 88 88 ED 
88 88 88 90  88 90 C4 88  88 88 E1 88  88 88 EF 88 
88 88 E0 88  88 88 FC 88  88 88 FB 88  88 88 91 88 
AC C4 88 88  88 ED 88 88  88 EE 88 88  88 FC 88 88 
88 A8 88 88  88 DC 88 88  88 FD 88 88  88 FA 88 88 
88 E6 88 88  88 92 88 A0  DA 88 88 88  E1 88 88 88 
EF 88 88 88  E0 88 88 88  FC 88 88 88  A8 88 88 88

The requirement doc says it is encoded XOR the byte against 0x77 then take the complementary byte.

So

59 XOR 77 => 2E (00101110) => D1 (11010001)
19 XOR 77 => 6E (01101110) => 91 (10010001)

What is the best way in node to do this and end with a buffer with the needed bytes?

Upvotes: 4

Views: 1847

Answers (2)

Arthur Weborg
Arthur Weborg

Reputation: 8580

dvlsg's answer is spot on functionally and received my upvote.

However, as they noted, their solution is "probably slower" (it's considerably slower -- though negligible for smaller buffers). The bitwise operators are performing calculations using 32-bit registers, yet if doing this bit manipulation byte by byte, it'll cost one 4x as many operations. In Addition to that. Array built in functions like .map and .forEach are doing a lot of tedious and unnecessary things behind the scenes for this low level crunching (those methods are geared toward immutability and functional programming -- a lot of data copying is going on behind the scenes during execution).

If you're doing binary manipulation, you most likely want to do the following instead:

// presuming `buffer` has your raw binary buffer
let wrapperUint32Array = new Uint32Array(buffer)
let end = wrapperUint32Array.length;
let i = 0;
while(i < end){
    wrapperUint32Array[i] = ~(0x77777777 ^ wrapperUint32Array[i])
    i++;
}

// your original buffer was manipulated/contains inverted bytes

Although, equally important to note, above only works if the buffer is divisible by 4 without remainders. If it's not, yet an even number of bytes are in the buffer, Uint16 could be used instead. If an odd number, Uint8 would need to be used like the following instead as well. We'd be performing more operations (similar in number to the Array map), but no data is being copied and iteration is still much quicker with this approach.

// presuming `buffer` has your raw binary buffer
let end = buffer.byteLength;
let i = 0;
let wrapperUint8Array = new Uint8Array(buffer)
while(i < end){
    wrapperUint8Array[i] = ~(0x77 ^ wrapperUint8Array[i])
    i++;
}

// your original buffer was manipulated/contains inverted bytes

Some key points:

  • We're taking full advantage of the 32-bitwise operators
  • buffer is shared within typed arrays -- no data is being copied
  • iteration of the buffer is optimal for performance

Upvotes: 1

dvlsg
dvlsg

Reputation: 5538

You could try this:

let buf = new Buffer([ 0x59, 0x19, 0xF2, 0x92 ]); // etc.
let converted = new Buffer(
    Array.from(buf)
        .map(x => x ^ 0x77)
        .map(x => ~x)
);

// output: <Buffer d1 91 7a 1a>

This probably won't be the fastest way (Array.from instead of just iterating over the buffer one by one is probably slower, and I opted for 2 separate maps instead of just 1 for readability) but it should at least get you started.

Upvotes: 3

Related Questions