forked from sheetjs/sheetjs
105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
|
|
import { Ptr, parse_varint49, write_varint49 } from './proto';
|
|
import { u8concat } from './util';
|
|
|
|
function is_framed(buf: Uint8Array): boolean {
|
|
var l = 0;
|
|
while(l < buf.length) {
|
|
l++;
|
|
var len = buf[l] | (buf[l+1]<<8) | (buf[l+2] << 16); l += 3;
|
|
l += len;
|
|
}
|
|
return l == buf.length;
|
|
}
|
|
export { is_framed };
|
|
|
|
function deframe(buf: Uint8Array): Uint8Array {
|
|
var out = [];
|
|
var l = 0;
|
|
while(l < buf.length) {
|
|
var t = buf[l++];
|
|
var len = buf[l] | (buf[l+1]<<8) | (buf[l+2] << 16); l += 3;
|
|
out.push(parse_snappy_chunk(t, buf.slice(l, l + len)));
|
|
l += len;
|
|
}
|
|
if(l !== buf.length) throw new Error("data is not a valid framed stream!");
|
|
return u8concat(out);
|
|
}
|
|
export { deframe };
|
|
|
|
function reframe(buf: Uint8Array): Uint8Array {
|
|
var out: Uint8Array[] = [];
|
|
var l = 0;
|
|
while(l < buf.length) {
|
|
var c = Math.min(buf.length - l, 0xFFFFFFF);
|
|
var frame = new Uint8Array(4);
|
|
out.push(frame);
|
|
var usz = write_varint49(c);
|
|
var L = usz.length;
|
|
out.push(usz);
|
|
|
|
if(c <= 60) { L++; out.push(new Uint8Array([(c - 1)<<2])); }
|
|
else if(c <= 0x100) { L += 2; out.push(new Uint8Array([0xF0, (c-1) & 0xFF])); }
|
|
else if(c <= 0x10000) { L += 3; out.push(new Uint8Array([0xF4, (c-1) & 0xFF, ((c-1) >> 8) & 0xFF])); }
|
|
else if(c <= 0x1000000) { L += 4; out.push(new Uint8Array([0xF8, (c-1) & 0xFF, ((c-1) >> 8) & 0xFF, ((c-1) >> 16) & 0xFF])); }
|
|
else if(c <= 0x100000000) { L += 5; out.push(new Uint8Array([0xFC, (c-1) & 0xFF, ((c-1) >> 8) & 0xFF, ((c-1) >> 16) & 0xFF, ((c-1) >>> 24) & 0xFF])); }
|
|
|
|
out.push(buf.slice(l, l + c)); L += c;
|
|
|
|
frame[0] = 0;
|
|
frame[1] = L & 0xFF; frame[2] = (L >> 8) & 0xFF; frame[3] = (L >> 16) & 0xFF;
|
|
l += c;
|
|
}
|
|
return u8concat(out);
|
|
}
|
|
export { reframe };
|
|
|
|
function parse_snappy_chunk(type: number, buf: Uint8Array): Uint8Array {
|
|
if(type != 0) throw new Error(`Unexpected Snappy chunk type ${type}`);
|
|
var ptr: Ptr = [0];
|
|
|
|
var usz = parse_varint49(buf, ptr);
|
|
var chunks = [];
|
|
while(ptr[0] < buf.length) {
|
|
var tag = buf[ptr[0]] & 0x3;
|
|
if(tag == 0) {
|
|
var len = buf[ptr[0]++] >> 2;
|
|
if(len < 60) ++len;
|
|
else {
|
|
var c = len - 59;
|
|
len = buf[ptr[0]];
|
|
if(c > 1) len |= (buf[ptr[0]+1]<<8);
|
|
if(c > 2) len |= (buf[ptr[0]+2]<<16);
|
|
if(c > 3) len |= (buf[ptr[0]+3]<<24);
|
|
len >>>=0; len++;
|
|
ptr[0] += c;
|
|
}
|
|
chunks.push(buf.slice(ptr[0], ptr[0] + len)); ptr[0] += len; continue;
|
|
} else {
|
|
var offset = 0, length = 0;
|
|
if(tag == 1) {
|
|
length = ((buf[ptr[0]] >> 2) & 0x7) + 4;
|
|
offset = (buf[ptr[0]++] & 0xE0) << 3;
|
|
offset |= buf[ptr[0]++];
|
|
} else {
|
|
length = (buf[ptr[0]++] >> 2) + 1;
|
|
if(tag == 2) { offset = buf[ptr[0]] | (buf[ptr[0]+1]<<8); ptr[0] += 2; }
|
|
else { offset = (buf[ptr[0]] | (buf[ptr[0]+1]<<8) | (buf[ptr[0]+2]<<16) | (buf[ptr[0]+3]<<24))>>>0; ptr[0] += 4; }
|
|
}
|
|
chunks = [u8concat(chunks)];
|
|
if(offset == 0) throw new Error("Invalid offset 0");
|
|
if(offset > chunks[0].length) throw new Error("Invalid offset beyond length");
|
|
if(length >= offset) {
|
|
chunks.push(chunks[0].slice(-offset)); length -= offset;
|
|
while(length >= chunks[chunks.length-1].length) {
|
|
chunks.push(chunks[chunks.length - 1]);
|
|
length -= chunks[chunks.length - 1].length;
|
|
}
|
|
}
|
|
chunks.push(chunks[0].slice(-offset, -offset + length));
|
|
}
|
|
}
|
|
var o = u8concat(chunks);
|
|
if(o.length != usz) throw new Error(`Unexpected length: ${o.length} != ${usz}`);
|
|
return o;
|
|
} |