Build a UCS-2 encoded HEX string from a Javascript default string encoding

280 Views Asked by At

How to build a UCS-2 encoded HEX string from a Javascript "basic" string, but only using web api (browser or Deno) features ?

In other words, how to convert the following node code but for the browser ?

message = "hello world "
const buf_le = Buffer.from(message, "ucs2"); // 'ucs2' is as same as 'utf16le'
let buf = Buffer.alloc(buf_le.length); // convert to utf16be (ucs2)
for (let i = 0; i < buf.length; i += 2)
  buf.writeUInt16BE(buf_le.readUInt16LE(i), i);
hex = buf.toString("hex");

It will be used to encode text to PDU for SMS sendings.

Thanks!

1

There are 1 best solutions below

3
On BEST ANSWER

You can use this solution from How to convert ArrayBuffer to and from String - Chrome Developers (usage of var updated to use const or let):

function str2ab(str) {
  const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
  const bufView = new Uint16Array(buf);
  for (let i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

It uses a Uint16Array as the view into the ArrayBuffer. "The Uint16Array typed array represents an array of 16-bit unsigned integers in the platform byte order. If control over byte order is needed, use DataView instead."

To get a hex representation there are several options:

  1. view the buf using a Uint16Array instance so that you don't need to concern yourself with your platform's byte order:

    function uint16Array2hex(array) {
      return Array.from(array, (b) => b.toString(16).padStart(4, "0")).join("");
    }
    
  2. update str2ab to use a DataView instead of Uint16Array so that you can write directly to network byte order (big endian):

    function str2ab(str) {
      const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
      const bufView = new DataView(buf);
      for (let i = 0, strLen = str.length; i < strLen; i++) {
        bufView.setUint16(2 * i, str.charCodeAt(i));
      }
      return buf;
    }
    
    function buf2hex(buf) {
      const bufView = new Uint8Array(buf);
      return Array.from(bufView, (b) => b.toString(16).padStart(2, "0")).join("");
    }
    
  3. Keep str2ab as-is from Chrome Developers and then convert from platform endianness to big-endian by reading from the buf using Uint16Array and writing to a buffer using a DataView like seen above.