formatting changes

* made lzari.js very es5-friendly.
* added jshint (yes, seriously) ruling to icon.js and lzari.js.
* Updated README.md
* Fixed up the werid mixed syntax on iconwriter.js
* -> basically made all the tab-based jank that only showed up correctly in...
* n++ a bit more readable outside of such. (minor tab to space consistancy fix)
* Added and removed semicolons to match some syntax standards.
* Made some things that should of been variables, variables !(global_leakage)
* expand module exporting code to clean up some 'object short notation' uses.
This commit is contained in:
yellows111 2024-02-21 01:45:19 +00:00
parent 8ab26610e6
commit a6ae91dffc
4 changed files with 133 additions and 120 deletions

View File

@ -6,9 +6,11 @@ A set of vertices with may or may not include a texture while defining colours f
## Why? ## Why?
Current implementations had some issues with rendering some icons. These were mostly: Current implementations had some issues with rendering some icons. These were mostly:
* Not rendering any color for texture type 3. * Not rendering any color for texture types 0-3.
* Failing to decompress some specific RLE-compressed icons. (types above 8) * Failing to decompress some specific RLE-compressed icons. (types with bit 4 enabled)
* Requires writing/reading a specific format for successful output of data. * Requires writing/reading a specific format for successful output of data.
* Incorrect analysis of texture types leading to assuming texture type 1 isn't the same group as texture type 3.
* Further incorrect analysis revealing it's that the texture type is a bitmask.
As of writing, there was no exporter that exists for the format that exhibited one of these problems. As of writing, there was no exporter that exists for the format that exhibited one of these problems.
@ -39,9 +41,9 @@ As of writing, there was no exporter that exists for the format that exhibited o
* Use any implementation-specific features. * Use any implementation-specific features.
## Client compatibility: ## Client compatibility:
The library requires use of `const`, `let` and `class` declarations. The library currently requires use of `const`, `let` and `class` declarations, template literals, and destructuring assignment for variables.
Any JavaScript implementation should work if they support all three of these declarations. Any JavaScript implementation should work if they support all of the required features.
### Tested clients: ### Tested clients:
* Chrome (or Blink-based browser) 49 (or higher) - HTML reference client * Chrome (or Blink-based browser) 49 (or higher) - HTML reference client
@ -52,13 +54,14 @@ Any JavaScript implementation should work if they support all three of these dec
Because it replaced what *was* left of icondumper (1). Because it replaced what *was* left of icondumper (1).
## Included files: ## Included files:
| File | Description | | File | Description |
| ---------------- | ----------------------------------------- | | ------------------- | ----------------------------------------------- |
| icon.js | The library itself. | | icon.js | The library itself. |
| index.js | Node.js example client. | | index.js | Node.js example client. |
| gltf-exporter.js | Node.js client to export icons to glTF 2. | | gltf-exporter.js | Node.js client to export icons to glTF 2. |
| index.htm | HTML reference client. | | index.htm | HTML reference client. |
| lzari.js | A LZARI decompression-only library. | | lzari.js | A LZARI decompression-only library. |
| tests/iconwriter.js | Node.js. Creates icons with texture types 0-31. |
## Included example files: ## Included example files:
| Directory | Description | Formats | | Directory | Description | Formats |

78
icon.js
View File

@ -1,4 +1,5 @@
//To swap between mjs/esm and c6js, go to the end of this file, and (un)comment your wanted module mode. //To swap between mjs/esm and c6js, go to the end of this file, and (un)comment your wanted module mode.
/* jshint bitwise: false, esversion: 6, -W009, -W010 */ // not doing this makes linters scream about BWOs, es6 features, and using new Primitive() instead of said primitives
var ICONJS_DEBUG = false; var ICONJS_DEBUG = false;
var ICONJS_STRICT = true; var ICONJS_STRICT = true;
@ -7,7 +8,7 @@ var ICONJS_STRICT = true;
* @constant {string} * @constant {string}
* @default * @default
*/ */
const ICONJS_VERSION = "0.8.2"; const ICONJS_VERSION = "0.8.3";
/** /**
* The RC4 key used for ciphering CodeBreaker Saves. * The RC4 key used for ciphering CodeBreaker Saves.
@ -62,22 +63,22 @@ class yellowDataReader extends DataView {
* @param {number} i Indice offset. * @param {number} i Indice offset.
* @returns {number} * @returns {number}
*/ */
u16le(i){return super.getUint16(i, 1)}; u16le(i){return super.getUint16(i, 1);}
/** Fixed-point 16-bit, Little Endian. /** Fixed-point 16-bit, Little Endian.
* @param {number} i Indice offset. * @param {number} i Indice offset.
* @returns {number} * @returns {number}
*/ */
f16le(i){return (super.getInt16(i, 1) / 4096)}; f16le(i){return (super.getInt16(i, 1) / 4096);}
/** Unsigned 32-bit, Little Endian. /** Unsigned 32-bit, Little Endian.
* @param {number} i Indice offset. * @param {number} i Indice offset.
* @returns {number} * @returns {number}
*/ */
u32le(i){return super.getUint32(i, 1)}; u32le(i){return super.getUint32(i, 1);}
/** Floating-point 32-bit, Little Endian. /** Floating-point 32-bit, Little Endian.
* @param {number} i Indice offset. * @param {number} i Indice offset.
* @returns {number} * @returns {number}
*/ */
f32le(i){return super.getFloat32(i, 1)}; f32le(i){return super.getFloat32(i, 1);}
/** 64-bit Timestamp structure, Little Endian. /** 64-bit Timestamp structure, Little Endian.
* Time returned is set for JST (UTC+09:00) instead of UTC. * Time returned is set for JST (UTC+09:00) instead of UTC.
* Time returned is going to be offseted for JST (GMT+09:00). * Time returned is going to be offseted for JST (GMT+09:00).
@ -97,7 +98,7 @@ class yellowDataReader extends DataView {
day: super.getUint8(i+4), day: super.getUint8(i+4),
month: super.getUint8(i+5), month: super.getUint8(i+5),
year: super.getUint16(i+6, 1) year: super.getUint16(i+6, 1)
}}; };}
constructor(buffer) { constructor(buffer) {
super(buffer); super(buffer);
return { return {
@ -106,7 +107,7 @@ class yellowDataReader extends DataView {
u32le: this.u32le.bind(this), u32le: this.u32le.bind(this),
f32le: this.f32le.bind(this), f32le: this.f32le.bind(this),
t64le: this.t64le.bind(this) t64le: this.t64le.bind(this)
} };
} }
} }
@ -213,7 +214,7 @@ function uncompressTexture(texData) {
uncompressed[index] = u16le(offset); uncompressed[index] = u16le(offset);
for (let indey = 0; indey < currentValue; indey++) { for (let indey = 0; indey < currentValue; indey++) {
uncompressed[index] = u16le(offset); uncompressed[index] = u16le(offset);
index++ index++;
} }
offset += 2; offset += 2;
} }
@ -285,13 +286,13 @@ function readPS2D(input) {
{x: f32le(80), y: f32le(84), z: f32le(88)}, //:skip 4 {x: f32le(80), y: f32le(84), z: f32le(88)}, //:skip 4
{x: f32le(96), y: f32le(100), z: f32le(104)}, //:skip 4 {x: f32le(96), y: f32le(100), z: f32le(104)}, //:skip 4
{x: f32le(112), y: f32le(116), z: f32le(120)} //:skip 4 {x: f32le(112), y: f32le(116), z: f32le(120)} //:skip 4
] ];
const lightColors = [ const lightColors = [
{r: f32le(128), g: f32le(132), b: f32le(136), a: f32le(140)}, {r: f32le(128), g: f32le(132), b: f32le(136), a: f32le(140)},
{r: f32le(144), g: f32le(148), b: f32le(152), a: f32le(156)}, {r: f32le(144), g: f32le(148), b: f32le(152), a: f32le(156)},
{r: f32le(160), g: f32le(164), b: f32le(168), a: f32le(172)}, {r: f32le(160), g: f32le(164), b: f32le(168), a: f32le(172)},
{r: f32le(176), g: f32le(180), b: f32le(184), a: f32le(188)} {r: f32le(176), g: f32le(180), b: f32le(184), a: f32le(188)}
] ];
// P2SB says color 1 is ambient, 2-4 are for 3-point cameras // P2SB says color 1 is ambient, 2-4 are for 3-point cameras
// official HDD icon.sys files (completely different PS2ICON text-based format) also say the same. // official HDD icon.sys files (completely different PS2ICON text-based format) also say the same.
const int_title = input.slice(0xc0, 0x100); const int_title = input.slice(0xc0, 0x100);
@ -317,7 +318,7 @@ function readPS2D(input) {
n: stringScrubber((new TextDecoder("utf-8")).decode(int_filename_n)), n: stringScrubber((new TextDecoder("utf-8")).decode(int_filename_n)),
c: stringScrubber((new TextDecoder("utf-8")).decode(int_filename_c)), c: stringScrubber((new TextDecoder("utf-8")).decode(int_filename_c)),
d: stringScrubber((new TextDecoder("utf-8")).decode(int_filename_d)) d: stringScrubber((new TextDecoder("utf-8")).decode(int_filename_d))
} };
if(ICONJS_DEBUG){ if(ICONJS_DEBUG){
console.debug({header, titleOffset, bgAlpha, bgColors, lightIndices, lightColors, title, filenames}); console.debug({header, titleOffset, bgAlpha, bgColors, lightIndices, lightColors, title, filenames});
} }
@ -339,7 +340,7 @@ function readIconFile(input) {
b: ((i & 0xff0000) >> 16), b: ((i & 0xff0000) >> 16),
a: (i > 0x7fffffff ? 255 : (((i & 0xff000000) >>> 24) * 2)+1) a: (i > 0x7fffffff ? 255 : (((i & 0xff000000) >>> 24) * 2)+1)
// I don't think alpha transparency is actually USED in icons?, rendering with it looks strange. // I don't think alpha transparency is actually USED in icons?, rendering with it looks strange.
}}; };};
const magic = u32le(0); const magic = u32le(0);
if (magic !== 0x010000) { if (magic !== 0x010000) {
// USER NOTICE: So far, I have yet to parse an icon that hasn't had 0x00010000 as it's magic. // USER NOTICE: So far, I have yet to parse an icon that hasn't had 0x00010000 as it's magic.
@ -354,7 +355,7 @@ function readIconFile(input) {
const textureFormat = getTextureFormat(textureType); const textureFormat = getTextureFormat(textureType);
//:skip 4 //:skip 4
const numberOfVertexes = u32le(16); const numberOfVertexes = u32le(16);
if(!!(numberOfVertexes % 3)){ if((numberOfVertexes % 3) > 0){
throw `Not enough vertices to define a triangle (${numberOfVertexes % 3} vertices remained).`; throw `Not enough vertices to define a triangle (${numberOfVertexes % 3} vertices remained).`;
} }
// format: [xxyyzzaa * numberOfShapes][xxyyzzaa][uuvvrgba], ((8 * numberOfShapes) + 16) [per chunk] // format: [xxyyzzaa * numberOfShapes][xxyyzzaa][uuvvrgba], ((8 * numberOfShapes) + 16) [per chunk]
@ -389,7 +390,7 @@ function readIconFile(input) {
vertices.push({shapes, normal, uv, color}); vertices.push({shapes, normal, uv, color});
} }
offset = (20+(numberOfVertexes * chunkLength)); offset = (20+(numberOfVertexes * chunkLength));
animationHeader = {id: u32le(offset), length: u32le(offset+4), speed: f32le(offset+8), "offset": u32le(offset+12), keyframes: u32le(offset+16)}; const animationHeader = {id: u32le(offset), length: u32le(offset+4), speed: f32le(offset+8), "offset": u32le(offset+12), keyframes: u32le(offset+16)};
let animData = new Array(); let animData = new Array();
// now we have to enumerate values, so now we introduce an offset value. // now we have to enumerate values, so now we introduce an offset value.
// format for a keyframe: sssskkkk[ffffvvvv] where [ffffvvvv] repeat based on the value that kkkk(eys) has. // format for a keyframe: sssskkkk[ffffvvvv] where [ffffvvvv] repeat based on the value that kkkk(eys) has.
@ -436,7 +437,7 @@ function readIconFile(input) {
//output of this will be another u16[0x4000] of the decompressed texture //output of this will be another u16[0x4000] of the decompressed texture
//after that just parse output as-if it was uncompressed. //after that just parse output as-if it was uncompressed.
//see uncompressTexture() and convertBGR5A1toRGB5A1() for more info. //see uncompressTexture() and convertBGR5A1toRGB5A1() for more info.
size = u32le(offset); const size = u32le(offset);
texture = {size, data: input.slice(offset+4, offset+(4+size))}; texture = {size, data: input.slice(offset+4, offset+(4+size))};
} }
} }
@ -497,7 +498,7 @@ function readEmsPsuFile(input){
let output = new Object(); let output = new Object();
let offset = 512; let offset = 512;
for (let index = 0; index < header.size; index++) { for (let index = 0; index < header.size; index++) {
fdesc = readEntryBlock(input.slice(offset, offset + 512)); const fdesc = readEntryBlock(input.slice(offset, offset + 512));
switch(fdesc.type) { switch(fdesc.type) {
case "directory": { case "directory": {
offset += 512; offset += 512;
@ -569,15 +570,21 @@ function readPsvFile(input){
for (let index = 0; index < numberOfFiles; index++) { for (let index = 0; index < numberOfFiles; index++) {
fileData.push(input.slice(offset,offset+0x3c)); fileData.push(input.slice(offset,offset+0x3c));
offset += 0x3c; offset += 0x3c;
}; }
//then file data after this but we already have pointers to the files we care about //then file data after this but we already have pointers to the files we care about
const icons = { const icons = {
n: input.slice(nModelOffset, nModelOffset+nModelSize), n: input.slice(nModelOffset, nModelOffset+nModelSize),
c: input.slice(cModelOffset, cModelOffset+cModelSize), c: input.slice(cModelOffset, cModelOffset+cModelSize),
d: input.slice(dModelOffset, dModelOffset+dModelSize), d: input.slice(dModelOffset, dModelOffset+dModelSize),
} };
if (ICONJS_DEBUG) { if (ICONJS_DEBUG) {
console.debug({magic, type1, type2, displayedSize, ps2dOffset, ps2dSize, nModelOffset, nModelSize, cModelOffset, cModelSize, dModelOffset, dModelSize, numberOfFiles, rootDirectoryData, fileData}) console.debug({magic, type1, type2, displayedSize,
ps2dOffset, ps2dSize,
nModelOffset, nModelSize,
cModelOffset, cModelSize,
dModelOffset, dModelSize,
numberOfFiles, rootDirectoryData, fileData
});
} }
return {icons, "icon.sys": input.slice(ps2dOffset, ps2dOffset+ps2dSize), timestamps}; return {icons, "icon.sys": input.slice(ps2dOffset, ps2dOffset+ps2dSize), timestamps};
} }
@ -660,11 +667,11 @@ function readSharkXPortSxpsFile(input) {
const comments = { const comments = {
"game": stringScrubber((new TextDecoder("utf-8")).decode(title)), "game": stringScrubber((new TextDecoder("utf-8")).decode(title)),
"name": stringScrubber((new TextDecoder("utf-8")).decode(description)) "name": stringScrubber((new TextDecoder("utf-8")).decode(description))
} };
if(description2Length !== 0) { if(description2Length !== 0) {
comments.desc = stringScrubber((new TextDecoder("utf-8")).decode(description2)); comments.desc = stringScrubber((new TextDecoder("utf-8")).decode(description2));
} }
const totalSize = u32le(offset); //const totalSize = u32le(offset); has data, unused in script
offset += 4; offset += 4;
const header = readSxpsDescriptor(input.slice(offset, offset + 250)); const header = readSxpsDescriptor(input.slice(offset, offset + 250));
offset += 250; offset += 250;
@ -672,7 +679,7 @@ function readSharkXPortSxpsFile(input) {
let fsOut = {length: header.size, rootDirectory: header.filename, timestamps: header.timestamps, comments}; let fsOut = {length: header.size, rootDirectory: header.filename, timestamps: header.timestamps, comments};
let output = new Object(); let output = new Object();
for (let index = 0; index < (header.size - 2); index++) { for (let index = 0; index < (header.size - 2); index++) {
fdesc = readSxpsDescriptor(input.slice(offset, offset + 250)); const fdesc = readSxpsDescriptor(input.slice(offset, offset + 250));
switch(fdesc.type) { switch(fdesc.type) {
case "directory": { case "directory": {
offset += 250; offset += 250;
@ -731,7 +738,7 @@ function readCodeBreakerCbsDirectory(input) {
*/ */
function readCodeBreakerCbsFile(input, inflator = null) { function readCodeBreakerCbsFile(input, inflator = null) {
if(typeof inflator !== "function") { if(typeof inflator !== "function") {
throw `No inflator function passed. Skipping.`; throw "No inflator function passed. Skipping.";
} }
const {u32le, t64le} = new yellowDataReader(input); const {u32le, t64le} = new yellowDataReader(input);
const magic = u32le(0); const magic = u32le(0);
@ -773,13 +780,13 @@ function readCodeBreakerCbsFile(input, inflator = null) {
*/ */
function readMaxPwsDirectory(input, directorySize) { function readMaxPwsDirectory(input, directorySize) {
const {u32le} = new yellowDataReader(input); const {u32le} = new yellowDataReader(input);
virtualFilesystem = new Object(); const virtualFilesystem = new Object();
let offset = 0; let offset = 0;
for (let index = 0; index < directorySize; index++) { for (let index = 0; index < directorySize; index++) {
const dataSize = u32le(offset); const dataSize = u32le(offset);
const _filename = input.slice(offset+4, offset+36); const _filename = input.slice(offset+4, offset+36);
const filename = stringScrubber((new TextDecoder("utf-8")).decode(_filename)); const filename = stringScrubber((new TextDecoder("utf-8")).decode(_filename));
if(filename === "") { throw `Unexpected null filename at byte ${offset+4}.`; }; if(filename === "") { throw `Unexpected null filename at byte ${offset+4}.`; }
offset += 36; offset += 36;
const data = input.slice(offset, offset+dataSize); const data = input.slice(offset, offset+dataSize);
offset += dataSize; offset += dataSize;
@ -802,12 +809,12 @@ function readMaxPwsDirectory(input, directorySize) {
*/ */
function readMaxPwsFile(input, unlzari) { function readMaxPwsFile(input, unlzari) {
if(typeof unlzari !== "function") { if(typeof unlzari !== "function") {
throw `No decompresser function passed. Skipping.`; throw "No decompresser function passed. Skipping.";
} }
const {u32le} = new yellowDataReader(input); const {u32le} = new yellowDataReader(input);
const ident = input.slice(0, 12); const ident = input.slice(0, 12);
if((new TextDecoder("utf-8")).decode(ident) !== "Ps2PowerSave") { if((new TextDecoder("utf-8")).decode(ident) !== "Ps2PowerSave") {
throw `Unrecognized file identification string. Expected "Ps2PowerSave".`; throw "Unrecognized file identification string. Expected \"Ps2PowerSave\".";
} }
//:skip 4 (u32 checksum) //:skip 4 (u32 checksum)
const _dirName = input.slice(0x10, 0x30); const _dirName = input.slice(0x10, 0x30);
@ -834,21 +841,22 @@ function readMaxPwsFile(input, unlzari) {
/** /**
* Define (module.)exports with all public functions. * Define (module.)exports with all public functions.
* @exports icondumper2/icon * @exports icondumper2/icon
*/ // start c6js */ // start c6js#
/* globals exports: true */
if(typeof exports !== "object") { if(typeof exports !== "object") {
exports = { exports = {
readers: {readIconFile, readPS2D, readEmsPsuFile, readPsvFile, readSharkXPortSxpsFile, readCodeBreakerCbsFile, readMaxPwsFile}, readers: {"readIconFile": readIconFile, "readPS2D": readPS2D, "readEmsPsuFile": readEmsPsuFile, "readPsvFile": readPsvFile, "readSharkXPortSxpsFile": readSharkXPortSxpsFile, "readCodeBreakerCbsFile": readCodeBreakerCbsFile, "readMaxPwsFile": readMaxPwsFile},
helpers: {uncompressTexture, convertBGR5A1toRGB5A1}, helpers: {"uncompressTexture": uncompressTexture, "convertBGR5A1toRGB5A1": convertBGR5A1toRGB5A1},
options: {setDebug, setStrictness}, options: {"setDebug": setDebug, "setStrictness": setStrictness},
version: ICONJS_VERSION version: ICONJS_VERSION
}; };
} else { } else {
exports.readers = {readIconFile, readPS2D, readEmsPsuFile, readPsvFile, readSharkXPortSxpsFile, readCodeBreakerCbsFile, readMaxPwsFile}; exports.readers = {"readIconFile": readIconFile, "readPS2D": readPS2D, "readEmsPsuFile": readEmsPsuFile, "readPsvFile": readPsvFile, "readSharkXPortSxpsFile": readSharkXPortSxpsFile, "readCodeBreakerCbsFile": readCodeBreakerCbsFile, "readMaxPwsFile": readMaxPwsFile};
exports.helpers = {uncompressTexture, convertBGR5A1toRGB5A1}; exports.helpers = {"uncompressTexture": uncompressTexture, "convertBGR5A1toRGB5A1": convertBGR5A1toRGB5A1};
exports.options = {setDebug, setStrictness}; exports.options = {"setDebug": setDebug, "setStrictness": setStrictness};
exports.version = ICONJS_VERSION; exports.version = ICONJS_VERSION;
} }
/* globals module: true */
if(typeof module !== "undefined") { if(typeof module !== "undefined") {
module.exports = exports; module.exports = exports;
} }

View File

@ -24,7 +24,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
**/ **/
/* jshint bitwise: false */ // not doing this makes linters scream about BWOs
//TODO: privatize variables and document the library //TODO: privatize variables and document the library
var inputData = null; var inputData = null;
@ -43,7 +43,7 @@ var bit_Mask = 0;
function GetBit() { function GetBit() {
//partial xgetc modification //partial xgetc modification
if(inputLocation >= inputData.length) {return -1}; if(inputLocation >= inputData.length) {return -1;}
if((bit_Mask >>= 1) === 0) { if((bit_Mask >>= 1) === 0) {
bit_Buffer = inputData[inputLocation++]; bit_Buffer = inputData[inputLocation++];
bit_Mask = 128; bit_Mask = 128;
@ -52,10 +52,10 @@ function GetBit() {
} }
function BinarySearchSym(x) { function BinarySearchSym(x) {
let i = 1; var i = 1;
let j = 314; var j = 314;
while (i < j) { while (i < j) {
let k = ((i + j) / 2)|0; var k = ((i + j) / 2)|0;
if (symbolCumulative[k] > x) { if (symbolCumulative[k] > x) {
i = k + 1; i = k + 1;
} else { } else {
@ -66,10 +66,10 @@ function BinarySearchSym(x) {
} }
function BinarySearchPos(x) { function BinarySearchPos(x) {
let i = 1; var i = 1;
let j = 4096; var j = 4096;
while (i < j) { while (i < j) {
let k = ((i + j) / 2)|0; var k = ((i + j) / 2)|0;
if (positionCumulative[k] > x) { if (positionCumulative[k] > x) {
i = k + 1; i = k + 1;
} else { } else {
@ -93,28 +93,28 @@ function DecodeChar() {
value -= 32768; value -= 32768;
low -= 32768; low -= 32768;
high -= 32768; high -= 32768;
} else if (high > 65536) { break }; } else if (high > 65536) { break; }
low += low; low += low;
high += high; high += high;
value = 2 * value + GetBit(); value = 2 * value + GetBit();
} }
//transcluded UpdateModel //transcluded UpdateModel
let character = symbolToCharacter[sym]; var character = symbolToCharacter[sym];
// do not remove above, will be overwritten otherwise! // do not remove above, will be overwritten otherwise!
let i; var i;
if(symbolCumulative[0] >= 32767) { if(symbolCumulative[0] >= 32767) {
let chr = 0; var chr = 0;
for (i = 314; i > 0; i--) { for (i = 314; i > 0; i--) {
symbolCumulative[i] = chr; symbolCumulative[i] = chr;
chr += (symbolFrequency[i] = (symbolFrequency[i] + 1) >> 1); chr += (symbolFrequency[i] = (symbolFrequency[i] + 1) >> 1);
} }
symbolCumulative[0] = chr; symbolCumulative[0] = chr;
} }
for(i = sym; symbolFrequency[i] === symbolFrequency[i - 1]; i--) {}; for(i = sym; symbolFrequency[i] === symbolFrequency[i - 1]; i--) {}
if (i < sym) { if (i < sym) {
let ch_i = symbolToCharacter[i]; var ch_i = symbolToCharacter[i];
let ch_sym = symbolToCharacter[sym]; var ch_sym = symbolToCharacter[sym];
symbolToCharacter[i] = ch_sym; symbolToCharacter[i] = ch_sym;
symbolToCharacter[sym] = ch_i; symbolToCharacter[sym] = ch_i;
characterToSymbol[ch_i] = sym; characterToSymbol[ch_i] = sym;
@ -144,7 +144,7 @@ function DecodePosition() {
value -= 32768; value -= 32768;
low -= 32768; low -= 32768;
high -= 32768; high -= 32768;
} else if (high > 65536) { break }; } else if (high > 65536) { break; }
low += low; low += low;
high += high; high += high;
value = 2 * value + GetBit(); value = 2 * value + GetBit();
@ -178,23 +178,22 @@ function decodeLzari(input) {
inputData = input; inputData = input;
inputLocation = 4; inputLocation = 4;
let dataSize = new DataView(input.buffer).getInt32(0,1); var dataSize = new DataView(input.buffer).getInt32(0,1);
if (dataSize == 0) return(0); if (dataSize == 0) return(0);
if (dataSize < 0) return(-1); if (dataSize < 0) return(-1);
let outputLength = dataSize; var outputData = new Uint8Array(dataSize);
let outputData = new Uint8Array(dataSize); var outputLocation = 0;
let outputLocation = 0;
//transcluded StartDecode //transcluded StartDecode
for (let i = 0; i < 17; i++) { for (var i = 0; i < 17; i++) {
value = 2 * value + GetBit(); value = 2 * value + GetBit();
} }
//transcluded StartModel //transcluded StartModel
symbolCumulative[314] = 0; symbolCumulative[314] = 0;
for (let sym = 314; sym >= 1; sym--) { for (var sym = 314; sym >= 1; sym--) {
let ch = sym - 1; var ch = sym - 1;
characterToSymbol[ch] = sym; characterToSymbol[ch] = sym;
symbolToCharacter[sym] = ch; symbolToCharacter[sym] = ch;
symbolFrequency[sym] = 1; symbolFrequency[sym] = 1;
@ -202,29 +201,29 @@ function decodeLzari(input) {
} }
symbolFrequency[0] = 0; symbolFrequency[0] = 0;
positionCumulative[4096] = 0; positionCumulative[4096] = 0;
for (let i = 4096; i >= 1; i--) { for (i = 4096; i >= 1; i--) { // redefine i
positionCumulative[i - 1] = (positionCumulative[i] + (10000 / (i + 200))|0); positionCumulative[i - 1] = (positionCumulative[i] + (10000 / (i + 200))|0);
} }
//end transclusion //end transclusion
//normal Decode process //normal Decode process
for (let i = 0; i < 4036; i++) { for (i = 0; i < 4036; i++) { // redefine i
text_buffer[i] = 32; text_buffer[i] = 32;
} }
var r = 4036; var r = 4036;
for (let count = 0; count < dataSize; ) { for (var count = 0; count < dataSize; ) {
if(inputLocation >= inputData.length) {break}; if(inputLocation >= inputData.length) {break;}
let c = DecodeChar(); var c = DecodeChar();
if (c < 256) { if (c < 256) {
outputData[outputLocation++] = c; outputData[outputLocation++] = c;
text_buffer[r++] = c; text_buffer[r++] = c;
r &= (4095); r &= (4095);
count++; count++;
} else { } else {
let i = (r - DecodePosition() - 1) & 4095; i = (r - DecodePosition() - 1) & 4095; // redefine i
let j = c - 253; var j = c - 253;
for (let k = 0; k < j; k++) { for (var k = 0; k < j; k++) {
c = text_buffer[(i + k) & 4095]; c = text_buffer[(i + k) & 4095];
outputData[outputLocation++] = c; outputData[outputLocation++] = c;
text_buffer[r++] = c; text_buffer[r++] = c;
@ -241,14 +240,15 @@ function decodeLzari(input) {
* Define (module.)exports with all public functions. * Define (module.)exports with all public functions.
* @exports icondumper2/lzari * @exports icondumper2/lzari
*/ // start c6js */ // start c6js
/* globals exports: true */
if(typeof exports !== "object") { if(typeof exports !== "object") {
exports = { exports = {
decodeLzari "decodeLzari": decodeLzari
}; };
} else { } else {
exports.decodeLzari = decodeLzari; exports.decodeLzari = decodeLzari;
} }
/* globals module: true */
if(typeof module !== "undefined") { if(typeof module !== "undefined") {
module.exports = exports; module.exports = exports;
} }

View File

@ -174,24 +174,25 @@ const animData = new Uint8Array([
0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00
]); // 36 bytes ]); // 36 bytes
/** generate texture data (RAW: fill with red) **/
const texture_ = new Uint16Array(16384); const texture_ = new Uint16Array(16384);
for (let indice = 0; indice < 16384; indice++) {
texture_[indice] = 0b1_00000_00000_11111; //A1BGR5
} // 32768 bytes
/** for compressed textures (RLE: fill with blue) **/ /** for compressed textures (RLE: fill with blue) **/
texture_[0] = 0x0004; texture_[0] = 0x0004;
texture_[1] = 0x0000; texture_[1] = 0x0000;
texture_[2] = 0x4000; texture_[2] = 0x4000;
texture_[3] = 0b1_11111_00000_00000; texture_[3] = 0b1_11111_00000_00000; // 16 bytes
/** generate texture data (RAW: fill with red) **/
for (let indice = 4; indice < 16384; indice++) {
texture_[indice] = 0b1_00000_00000_11111; //A1BGR5
} // 32768 bytes
const textureData = new Uint8Array(texture_.buffer); const textureData = new Uint8Array(texture_.buffer);
/** ps2d data **/ /** ps2d data **/
const metadataSkeleton = new Uint8Array(Array.from({...[ const metadataSkeleton = new Uint8Array(Array.from({...[
0x50, 0x53, 0x32, 0x44, 0x00, 0x00, 0x50, 0x53, 0x32, 0x44, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, // PS2D files have a max limit of 16 characters per line 0x20, 0x00, 0x00, 0x00, // PS2D files have a max limit of 16 characters per line
0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
// color1.rgba // color1.rgba
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -226,41 +227,41 @@ const metadataSkeleton = new Uint8Array(Array.from({...[
0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f,
0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00,
// title // title
0x82, 0x89, 0x82, 0x83, 0x82, 0x8f, 0x82, 0x8e, // icon 0x82, 0x89, 0x82, 0x83, 0x82, 0x8f, 0x82, 0x8e, // icon
0x82, 0x84, 0x82, 0x95, 0x82, 0x8d, 0x82, 0x90, // dump 0x82, 0x84, 0x82, 0x95, 0x82, 0x8d, 0x82, 0x90, // dump
0x82, 0x85, 0x82, 0x92, 0x82, 0x51, 0x81, 0x40, // er2 0x82, 0x85, 0x82, 0x92, 0x82, 0x51, 0x81, 0x40, // er2
0x82, 0x73, 0x82, 0x85, 0x82, 0x93, 0x82, 0x94, // Test 0x82, 0x73, 0x82, 0x85, 0x82, 0x93, 0x82, 0x94, // Test
0x82, 0x73, 0x82, 0x85, 0x82, 0x98, 0x82, 0x94, // Text 0x82, 0x73, 0x82, 0x85, 0x82, 0x98, 0x82, 0x94, // Text
0x82, 0x95, 0x82, 0x92, 0x82, 0x85, 0x81, 0x40, // ure 0x82, 0x95, 0x82, 0x92, 0x82, 0x85, 0x81, 0x40, // ure
0x82, 0x73, 0x82, 0x99, 0x82, 0x90, 0x82, 0x85, // Type 0x82, 0x73, 0x82, 0x99, 0x82, 0x90, 0x82, 0x85, // Type
0x81, 0x40, 0x82, 0x58, // 9 0x81, 0x40, 0x82, 0x58, // 9
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// file - normal // file - normal
0x74, 0x65, 0x78, 0x74, 0x79, 0x70, 0x65, 0x31, 0x74, 0x65, 0x78, 0x74, 0x79, 0x70, 0x65, 0x31,
0x2E, 0x69, 0x63, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x69, 0x63, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// file - copying // file - copying
0x74, 0x65, 0x78, 0x74, 0x79, 0x70, 0x65, 0x31, 0x74, 0x65, 0x78, 0x74, 0x79, 0x70, 0x65, 0x31,
0x2E, 0x69, 0x63, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x69, 0x63, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// file - deleting // file - deleting
0x74, 0x65, 0x78, 0x74, 0x79, 0x70, 0x65, 0x31, 0x74, 0x65, 0x78, 0x74, 0x79, 0x70, 0x65, 0x31,
0x2E, 0x69, 0x63, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x69, 0x63, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//], length:964})); //], length:964}));
], length:1024})); // psu want block size ], length:1024})); // psu want block size
@ -271,6 +272,7 @@ CombinedIconData.set(iconData, 20);
CombinedIconData.set(animData, 20+864); CombinedIconData.set(animData, 20+864);
CombinedIconData.set(textureData, 20+864+36); CombinedIconData.set(textureData, 20+864+36);
// to be honest all of this could just be a generator
/** root directory **/ /** root directory **/
const psuHeader1 = new Uint8Array(Array.from({...[ const psuHeader1 = new Uint8Array(Array.from({...[
0x27, 0x84, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x27, 0x84, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
@ -321,7 +323,7 @@ const psuHeader4 = new Uint8Array(Array.from({...[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x69, 0x63, 0x6f, 0x6e, 0x2e, 0x73, 0x79, 0x73 0x69, 0x63, 0x6f, 0x6e, 0x2e, 0x73, 0x79, 0x73
], length:512})); ], length:512}));
/** textypeX.icn **/ /** textypeX.icn **/
@ -334,7 +336,7 @@ const psuHeader5 = new Uint8Array(Array.from({...[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x74, 0x65, 0x78, 0x74, 0x79, 0x70, 0x65, 0x39, 0x74, 0x65, 0x78, 0x74, 0x79, 0x70, 0x65, 0x39,
0x2E, 0x69, 0x63, 0x6E 0x2E, 0x69, 0x63, 0x6E
], length:512})); ], length:512}));
@ -344,10 +346,10 @@ for (let iconIndice = 0; iconIndice < 32; iconIndice++) { // realistically only
if(iconIndice > 9) { if(iconIndice > 9) {
needsAlpha = 7; // if we're past 9, offset to start at A instead needsAlpha = 7; // if we're past 9, offset to start at A instead
} }
const PsuFileOutput = new Uint8Array(37888); // 37 uncompressed blocks const PsuFileOutput = new Uint8Array(37888);// 37 uncompressed blocks
CombinedIconData[8] = iconIndice; // set texture type CombinedIconData[8] = iconIndice; // set texture type
psuHeader1[75] = 0x30 + iconIndice+needsAlpha; // set folder name psuHeader1[75] = 0x30 + iconIndice+needsAlpha; // set folder name
psuHeader5[71] = 0x30 + iconIndice+needsAlpha; // set file name psuHeader5[71] = 0x30 + iconIndice+needsAlpha; // set file name
metadataSkeleton[251] = 0x4f + iconIndice+needsAlpha; // set display name metadataSkeleton[251] = 0x4f + iconIndice+needsAlpha; // set display name
metadataSkeleton[267] = 0x30 + iconIndice+needsAlpha; // set normal file name metadataSkeleton[267] = 0x30 + iconIndice+needsAlpha; // set normal file name
metadataSkeleton[331] = 0x30 + iconIndice+needsAlpha; // set copy file name metadataSkeleton[331] = 0x30 + iconIndice+needsAlpha; // set copy file name