scratch-sb1-converter
Version:
Scratch 1 (.sb) to Scratch 2 (.sb2) conversion library for Scratch 3.0
209 lines (190 loc) • 5.39 kB
JavaScript
import {TextDecoder as JSTextDecoder} from 'text-encoding';
import {assert} from '../util/assert';
import {IS_HOST_LITTLE_ENDIAN, Int16BE, BytePrimitive, Uint8, Uint32BE} from '../coders/byte-primitives';
const BUFFER_TOO_BIG = 10 * 1024 * 1024;
/**
* @const ReferenceBE
* @type BytePrimitive
*/
let ReferenceBE;
if (IS_HOST_LITTLE_ENDIAN) {
ReferenceBE = new BytePrimitive({
size: 3,
read (uint8a, position) {
return (
(uint8a[position + 0] << 16) |
(uint8a[position + 1] << 8) |
uint8a[position + 2]
);
}
});
} else {
ReferenceBE = new BytePrimitive({
size: 3,
read (uint8a, position) {
return (
(uint8a[position + 2] << 16) |
(uint8a[position + 1] << 8) |
uint8a[position + 0]
);
}
});
}
/**
* @const LargeInt
* @type BytePrimitive
*/
const LargeInt = new BytePrimitive({
sizeOf (uint8a, position) {
const count = Int16BE.read(uint8a, position);
return Int16BE.size + count;
},
read (uint8a, position) {
let num = 0;
let multiplier = 0;
const count = Int16BE.read(uint8a, position);
for (let i = 0; i < count; i++) {
num = num + (multiplier * Uint8.read(uint8a, position++));
multiplier *= 256;
}
return num;
}
});
/**
* @const AsciiString
* @type BytePrimitive
*/
const AsciiString = new BytePrimitive({
sizeOf (uint8a, position) {
const count = Uint32BE.read(uint8a, position);
return Uint32BE.size + count;
},
read (uint8a, position) {
const count = Uint32BE.read(uint8a, position);
assert(count < BUFFER_TOO_BIG, 'asciiString too big');
position += 4;
let str = '';
for (let i = 0; i < count; i++) {
str += String.fromCharCode(uint8a[position++]);
}
return str;
}
});
/**
* @const Bytes
* @type BytePrimitive
*/
const Bytes = new BytePrimitive({
sizeOf (uint8a, position) {
return Uint32BE.size + Uint32BE.read(uint8a, position);
},
read (uint8a, position) {
const count = Uint32BE.read(uint8a, position);
assert(count < BUFFER_TOO_BIG, 'bytes too big');
position += Uint32BE.size;
assert(count < BUFFER_TOO_BIG, 'uint8a array too big');
return new Uint8Array(uint8a.buffer, position, count);
}
});
/**
* @const SoundBytes
* @type BytePrimitive
*/
const SoundBytes = new BytePrimitive({
sizeOf (uint8a, position) {
return Uint32BE.size + (Uint32BE.read(uint8a, position) * 2);
},
read (uint8a, position) {
const samples = Uint32BE.read(uint8a, position);
assert(samples < BUFFER_TOO_BIG, 'sound too big');
position += Uint32BE.size;
const count = samples * 2;
assert(count < BUFFER_TOO_BIG, 'uint8a array too big');
return new Uint8Array(uint8a.buffer, position, count);
}
});
/**
* @const Bitmap32BE
* @type BytePrimitive
*/
const Bitmap32BE = new BytePrimitive({
sizeOf (uint8a, position) {
return Uint32BE.size + (Uint32BE.read(uint8a, position) * Uint32BE.size);
},
read (uint8a, position) {
const count = Uint32BE.read(uint8a, position);
assert(count < BUFFER_TOO_BIG, 'bitmap too big');
position += Uint32BE.size;
assert(count < BUFFER_TOO_BIG, 'uint8a array too big');
const value = new Uint32Array(count);
for (let i = 0; i < count; i++) {
value[i] = Uint32BE.read(uint8a, position);
position += Uint32BE.size;
}
return value;
}
});
let decoder;
if (typeof TextDecoder === 'undefined') {
decoder = new JSTextDecoder();
} else {
decoder = new TextDecoder();
}
/**
* @const UTF8
* @type BytePrimitive
*/
const UTF8 = new BytePrimitive({
sizeOf (uint8a, position) {
return Uint32BE.size + Uint32BE.read(uint8a, position);
},
read (uint8a, position) {
const count = Uint32BE.read(uint8a, position);
assert(count < BUFFER_TOO_BIG, 'utf8 too big');
position += Uint32BE.size;
assert(count < BUFFER_TOO_BIG, 'uint8a array too big');
return decoder.decode(new Uint8Array(uint8a.buffer, position, count));
}
});
/**
* @const OpaqueColor
* @type BytePrimitive
*/
const OpaqueColor = new BytePrimitive({
size: 4,
read (uint8a, position) {
const rgb = Uint32BE.read(uint8a, position);
const a = 0xff;
const r = (rgb >> 22) & 0xff;
const g = (rgb >> 12) & 0xff;
const b = (rgb >> 2) & 0xff;
return ((a << 24) | (r << 16) | (g << 8) | b) >>> 0;
}
});
/**
* @const TranslucentColor
* @type BytePrimitive
*/
const TranslucentColor = new BytePrimitive({
size: 5,
read (uint8a, position) {
const rgb = Uint32BE.read(uint8a, position);
const a = Uint8.read(uint8a, position);
const r = (rgb >> 22) & 0xff;
const g = (rgb >> 12) & 0xff;
const b = (rgb >> 2) & 0xff;
return ((a << 24) | (r << 16) | (g << 8) | b) >>> 0;
}
});
export {
BUFFER_TOO_BIG,
ReferenceBE,
LargeInt,
AsciiString,
Bytes,
SoundBytes,
Bitmap32BE,
UTF8,
OpaqueColor,
TranslucentColor
};