| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview A grab-bag of utilities. |
| */ |
| |
| // TextDecoder doesn't come with quickjs. |
| /** |
| * Produces a String given an array of UTF-16 codepoints. |
| * |
| * @param {Number[]} codePoints An array of codepoints to convert to a String |
| */ |
| function codePointsToString(codePoints) { |
| let s = ''; |
| let i = 0; |
| const length = codePoints.length; |
| const BATCH_SIZE = 10000; |
| while (i < length) { |
| const end = Math.min(i + BATCH_SIZE, length); |
| const slice = codePoints.slice(i, end); |
| s += String.fromCodePoint.apply(null, slice); |
| i = end; |
| } |
| return s; |
| } |
| |
| /** |
| * Produces a String from a DataView into UTF-8 bytes. |
| * |
| * @param {DataView} bytes A view into an array of UTF-8 bytes to convert to a String. |
| */ |
| function decodeUtf8(bytes) { |
| let offset = 0; |
| const codePoints = []; |
| while (offset < bytes.byteLength) { |
| const c = bytes.getUint8(offset++); |
| if (c < 0x80) { // Regular 7-bit ASCII. |
| codePoints.push(c); |
| } else if (c < 0xC0) { |
| // UTF-8 continuation mark. We are out of sync. This |
| // might happen if we attempted to read a character |
| // with more than four bytes. |
| continue; |
| } else if (c < 0xE0) { // UTF-8 with two bytes. |
| const c2 = bytes.getUint8(offset++); |
| codePoints.push(((c & 0x1F) << 6) | (c2 & 0x3F)); |
| } else if (c < 0xF0) { // UTF-8 with three bytes. |
| const c2 = bytes.getUint8(offset++); |
| const c3 = bytes.getUint8(offset++); |
| codePoints.push(((c & 0xF) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)); |
| } else if (c < 0xF8) { // UTF-8 with 4 bytes. |
| const c2 = bytes.getUint8(offset++); |
| const c3 = bytes.getUint8(offset++); |
| const c4 = bytes.getUint8(offset++); |
| // Characters written on 4 bytes have 21 bits for a codepoint. |
| // We can't fit that on 16bit characters, so we use surrogates. |
| let codepoint = ((c & 0x07) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F); |
| codePoints.push(codepoint); |
| } |
| } |
| return codePointsToString(codePoints); |
| } |
| |
| /** |
| * Returns whether the two arrays are equal. |
| * |
| * @param {Any[]} a |
| * @param {Any[]} b |
| */ |
| function arraysEqual(a, b) { |
| if (a === b) { |
| return true; |
| } |
| if (a == null || b == null) { |
| return false; |
| } |
| if (a.length != b.length) { |
| return false; |
| } |
| for (var i = 0; i < a.length; ++i) { |
| if (a[i] !== b[i]) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Returns whether a is a prefix of b. |
| * |
| * @param {Any[]} a |
| * @param {Any[]} b |
| */ |
| function isPrefixOf(a, b) { |
| if (a === b) { |
| return true; |
| } |
| if (a == null || b == null) { |
| return false; |
| } |
| if (a.length > b.length) { |
| return false; |
| } |
| for (let i = 0; i < a.length; i++) { |
| if (a[i] != b[i]) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| export {isPrefixOf, arraysEqual, codePointsToString, decodeUtf8} |