Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- This file is part of Phantasy Star Portable Tools
- Copyright 2019 Benjamin Collins (kion at dashgl dot com)
- Prs function adapted to Javascript from:
- http://forums.qhimm.com/index.php?topic=11225.0
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- "use strict";
- const gasetools = {
- nbl: function(arraybuffer) {
- const files = {};
- const data = arraybuffer;
- const view = new DataView(arraybuffer);
- /**
- * READ HEADER
- **/
- const MAGIC_NMLL = 0x4c4c4d4e;
- const nmll_magic = view.getUint32(0, true);
- const compression_format = view.getUint8(0x05);
- const is_encrypted = view.getUint32(0x1c, true);
- const key = new Uint8Array(4);
- key[0] = view.getUint8(0x1C + 3);
- key[1] = view.getUint8(0x1C + 2);
- key[2] = view.getUint8(0x1C + 1);
- key[3] = view.getUint8(0x1C + 0);
- const fish = new Blowfish(key);
- const nmll = {
- header_size: view.getUint32(0x08, true),
- chunk_count: view.getUint32(0x0c, true),
- full_length: view.getUint32(0x10, true),
- comp_length: view.getUint32(0x14, true),
- pointer_len: view.getUint32(0x18, true)
- };
- const tmll = {
- header_size: view.getUint32(0x20, true),
- full_length: view.getUint32(0x24, true),
- comp_length: view.getUint32(0x28, true),
- chunk_count: view.getUint32(0x2c, true)
- }
- /**
- * READ NMLL SECTION
- **/
- let ofs = 0x40;
- if (is_encrypted) {
- for (let i = 0; i < nmll.chunk_count; i++) {
- for (let k = ofs; k < ofs + 0x30; k += 8) {
- fish.bf_decrypt(view, k);
- }
- ofs += 0x60;
- }
- }
- console.log("Reading File List:");
- console.log("a bebe");
- ofs = 0x40;
- nmll.files = new Array(nmll.chunk_count);
- for (let i = 0; i < nmll.chunk_count; i++) {
- let name = "";
- for (let k = 0; k < 0x20; k++) {
- let ch = view.getUint8(ofs + k);
- if (ch === 0) {
- break;
- }
- name += String.fromCharCode(ch);
- }
- nmll.files[i] = {
- name: name,
- start: view.getUint32(ofs + 0x20, true),
- length: view.getUint32(ofs + 0x24, true)
- };
- ofs += 0x60;
- }
- console.log(nmll.files);
- if (ofs % 0x800 !== 0) {
- ofs = (ofs & 0xfffff800) + 0x800;
- }
- // Check for empty Nbl
- if (ofs >= data.byteLength) {
- return files;
- }
- const nmll_len = nmll.comp_length || nmll.full_length;
- let nmll_data = data.slice(ofs, ofs + nmll_len);
- if (is_encrypted) {
- const rounded = Math.floor(nmll_len / 8) * 8;
- const nmll_view = new DataView(nmll_data);
- for (let i = 0; i < rounded; i += 8) {
- fish.bf_decrypt(nmll_view, i);
- }
- }
- console.log(nmll_data);
- console.log("NMLL Length: 0x%s", nmll_data.byteLength.toString(16));
- if (nmll.comp_length) {
- switch (compression_format) {
- case 0x00:
- case 0x40:
- nmll_data = gasetools.prs(nmll_data);
- break;
- case 0x10:
- console.log("This compression format is not supported");
- return files;
- break;
- default:
- console.log("There is another compression format?: 0x%s", compression_format.toString(16));
- break;
- }
- }
- console.log("NMLL Length: 0x%s", nmll_data.byteLength.toString(16));
- ofs += nmll_len;
- ofs = (ofs & 0xfffff800) + 0x800;
- const pointer_table = new Array();
- for (let i = 0; i < nmll.pointer_len; i += 4) {
- pointer_table.push(view.getUint32(ofs + i, true));
- }
- ofs += nmll.pointer_len;
- if (ofs % 0x800) {
- ofs = (ofs & 0xfffff800) + 0x800;
- }
- const nmll_view = new DataView(nmll_data);
- for (let i = 0; i < nmll.files.length; i++) {
- let f = nmll.files[i];
- let start = f.start;
- let end = f.start + f.length;
- let locals = [];
- for (let k = 0; k < pointer_table.length; k++) {
- if (pointer_table[k] < start || pointer_table[k] >= end) {
- continue;
- }
- let dword = nmll_view.getUint32(pointer_table[k], true);
- dword -= start;
- if (dword < 0) {
- continue;
- }
- nmll_view.setUint32(dword, true);
- }
- let buffer = nmll_data.slice(start, end);
- files[f.name] = buffer;
- }
- if (ofs >= data.byteLength) {
- console.log("THIS IS THE END (NMLL ONRY)");
- return files;
- }
- const MAGIC_TMLL = 0x4c4c4d54;
- const tmll_magic = view.getUint32(ofs, true);
- if (tmll_magic !== MAGIC_TMLL) {
- console.log("NO TMLL? IS THIS RIGHT?");
- return files;
- }
- /**
- * TMLL SECTION
- **/
- console.log("STarting TMLL Section");
- const tmll_start = ofs;
- ofs = tmll_start + 0x30;
- if (is_encrypted) {
- for (let i = 0; i < nmll.chunk_count; i++) {
- for (let k = ofs; k < ofs + 0x30; k += 8) {
- fish.bf_decrypt(view, k);
- }
- ofs += 0x60;
- }
- }
- console.log("Reading File List:");
- ofs = tmll_start + 0x30;
- tmll.files = new Array(tmll.chunk_count);
- for (let i = 0; i < nmll.chunk_count; i++) {
- let name = "";
- for (let k = 0; k < 0x20; k++) {
- let ch = view.getUint8(ofs + k);
- if (ch === 0) {
- break;
- }
- name += String.fromCharCode(ch);
- }
- tmll.files[i] = {
- name: name,
- start: view.getUint32(ofs + 0x20, true),
- length: view.getUint32(ofs + 0x24, true)
- };
- ofs += 0x60;
- }
- if (ofs % 0x800) {
- ofs = (ofs & 0xfffff800) + 0x800;
- }
- console.log(tmll.files);
- const tmll_len = tmll.comp_length || tmll.full_length;
- let tmll_data = data.slice(ofs, ofs + tmll_len);
- if (tmll.comp_length) {
- switch (compression_format) {
- case 0x00:
- case 0x40:
- tmll_data = gasetools.prs(tmll_data);
- break;
- case 0x10:
- console.log("This compression format is not supported");
- return files;
- break;
- default:
- console.log("0x%s", compression_format.toString(16));
- break;
- }
- }
- for (let i = 0; i < tmll.files.length; i++) {
- let f = tmll.files[i];
- let start = f.start;
- let end = f.start + f.length;
- let buffer = tmll_data.slice(start, end);
- files[f.name] = buffer;
- }
- return files;
- },
- prs: function(arraybuffer) {
- const self = {
- ibuf: new Uint8Array(arraybuffer),
- obuf: [],
- iofs: 0,
- bit: 0,
- cmd: 0,
- getByte: int_getByte,
- getBit: bool_getBit
- }
- let t, a, b, j, cmd;
- let offset, amount, start;
- while (self.iofs < self.ibuf.length) {
- cmd = self.getBit();
- if (cmd) {
- self.obuf.push(self.ibuf[self.iofs]);
- self.iofs += 1;
- } else {
- t = self.getBit();
- if (t) {
- a = self.getByte();
- b = self.getByte();
- offset = ((b << 8) | a) >> 3;
- amount = a & 7;
- if (self.iofs < self.ibuf.length) {
- if (amount == 0)
- amount = self.getByte() + 1;
- else
- amount += 2;
- }
- start = self.obuf.length - 0x2000 + offset;
- } else {
- amount = 0;
- for (j = 0; j < 2; j++) {
- amount <<= 1;
- amount |= self.getBit();
- }
- offset = self.getByte();
- amount += 2;
- start = self.obuf.length - 0x100 + offset;
- }
- for (j = 0; j < amount; j++) {
- if (start < 0)
- self.obuf.push(0);
- else if (start < self.obuf.length)
- self.obuf.push(self.obuf[start]);
- else
- self.obuf.push(0);
- start += 1;
- }
- }
- } //end while
- return new Uint8Array(self.obuf).buffer;
- function int_getByte() {
- let val = self.ibuf[self.iofs];
- self.iofs += 1;
- return parseInt(val);
- }
- function bool_getBit() {
- if (self.bit == 0) {
- self.cmd = self.getByte()
- self.bit = 8
- }
- let bit = self.cmd & 1;
- self.cmd >>= 1;
- self.bit -= 1;
- return parseInt(bit);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement