1 /* Schoinion - Scatter-Gather Buffer Routines
2 * Copyright (C) 2017 Jay Freeman (saurik)
5 /* GNU Affero General Public License, Version 3 {{{ */
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 import * as assert from 'assert';
23 import atob = require('atob');
24 import btoa = require('btoa');
25 import * as te from 'text-encoding';
27 const encoder = new te.TextEncoder();
28 const decoder = new te.TextDecoder();
30 export function utf8encode(data: string): Uint8Array {
31 return encoder.encode(data);
34 export function utf8decode(data: Uint8Array): string {
35 return decoder.decode(data);
38 export function asc2encode(data: string): Uint8Array {
39 const buffer = new ArrayBuffer(data.length);
40 const array = new Uint8Array(buffer);
41 for (let i = 0; i !== data.length; ++i)
42 array[i] = data.charCodeAt(i);
46 export function asc2decode(data: Uint8Array): string {
47 return String.fromCharCode.apply(null, data);
50 export function js1encode(data: any): Uint8Array {
51 return utf8encode(JSON.stringify(data));
54 export function js1decode(data: Uint8Array): any {
55 return JSON.parse(utf8decode(data));
58 export function b64encode(data: Uint8Array): string {
59 return btoa(asc2decode(data)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
62 export function b64decode(data: string): Uint8Array {
63 return asc2encode(atob(data.replace(/-/g, "+").replace(/_/g, "/")));
67 export function ie3encode(data: number): Uint8Array {
68 const array = new Float64Array(1);
70 return new Uint8Array(array.buffer);
73 export function ie3decode(data: Uint8Array): number {
74 assert.ok(data.length === 8);
75 const array = new Float64Array(data.buffer, data.byteOffset, 1);
80 export function join(parts: Uint8Array[]): Uint8Array {
82 parts.forEach((part) => total += part.length);
83 const joined = new Uint8Array(total);
86 parts.forEach((part) => {
87 if (part.constructor !== Uint8Array)
88 part = new Uint8Array(part.buffer, part.byteOffset, part.byteLength);
89 joined.set(part, offset);
90 offset += part.length;
96 export function part(data: Uint8Array, sizes: number[]): Uint8Array[] {
97 const parted = new Array<Uint8Array>();
99 sizes.forEach((size) => {
101 size = data.length - offset;
102 const end = offset + size;
103 assert.ok(data.length >= end);
104 parted.push(data.subarray(offset, end));
107 assert.ok(data.length === offset);
111 export function concat<T>(data: T[][]): T[] {
112 return Array.prototype.concat.apply([], data);
116 export interface Kind {
117 readonly BYTES_PER_ELEMENT: number;
118 new(length: number): ArrayLike<number> & ArrayBufferView;
119 new(array: ArrayLike<number>): ArrayLike<number> & ArrayBufferView;
120 new(buffer: ArrayBufferLike, offset?: number, length?: number): ArrayLike<number> & ArrayBufferView;
123 export function num(kind: Kind, data: Uint8Array): number {
124 assert.ok(data.length === kind.BYTES_PER_ELEMENT);
125 return new kind(data.buffer, data.byteOffset, 1)[0];
128 export function buf(kind: Kind, value: number): Uint8Array {
129 return new Uint8Array(new kind([value]).buffer);
133 export function xor(lhs: Uint8Array, rhs: Uint8Array): Uint8Array {
134 const length = lhs.length;
135 assert.ok(rhs.length === length);
136 const value = new Uint8Array(length);
137 for (let index = length; index-- !== 0; )
138 value[index] = lhs[index] ^ rhs[index];
142 export function add(lhs: Uint8Array, rhs: Uint8Array): Uint8Array {
143 const length = lhs.length;
144 assert.ok(rhs.length === length);
145 const value = new Uint8Array(length);
147 for (let index = length; index-- !== 0; ) {
148 const next = lhs[index] + (rhs[index] + carry);
150 carry = (next & 0x100) !== 0 ? 1 : 0;
155 export function sub(lhs: Uint8Array, rhs: Uint8Array): Uint8Array {
156 const length = lhs.length;
157 assert.ok(rhs.length === length);
158 const value = new Uint8Array(length);
160 for (let index = length; index-- !== 0; ) {
161 const next = lhs[index] - (rhs[index] + carry);
163 carry = (next & 0x100) !== 0 ? 1 : 0;
168 export function cmp(lhs: Uint8Array, rhs: Uint8Array): number {
169 const length = lhs.length;
170 assert.ok(rhs.length === length);
171 for (let index = 0; index !== length; ++index)
172 if (lhs[index] !== rhs[index])
173 return lhs[index] < rhs[index] ? -1 : 1;
177 export function max(length: number): Uint8Array {
178 return new Uint8Array(length).fill(0xff);