Advertisement
Guest User

Gasetools.js

a guest
Dec 31st, 2019
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  
  3.     This file is part of Phantasy Star Portable Tools
  4.     Copyright 2019 Benjamin Collins (kion at dashgl dot com)
  5.  
  6.     Prs function adapted to Javascript from:
  7.     http://forums.qhimm.com/index.php?topic=11225.0
  8.  
  9.     Permission is hereby granted, free of charge, to any person obtaining
  10.     a copy of this software and associated documentation files (the
  11.     "Software"), to deal in the Software without restriction, including
  12.     without limitation the rights to use, copy, modify, merge, publish,
  13.     distribute, sublicense, and/or sell copies of the Software, and to
  14.     permit persons to whom the Software is furnished to do so, subject to
  15.     the following conditions:
  16.  
  17.     The above copyright notice and this permission notice shall be included
  18.     in all copies or substantial portions of the Software.
  19.  
  20.     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  21.     OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22.     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  23.     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  24.     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  25.     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  26.     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27.  
  28. */
  29. "use strict";
  30.  
  31. const gasetools = {
  32.  
  33.     nbl: function(arraybuffer) {
  34.  
  35.         const files = {};
  36.         const data = arraybuffer;
  37.         const view = new DataView(arraybuffer);
  38.  
  39.         /**
  40.          * READ HEADER
  41.          **/
  42.  
  43.         const MAGIC_NMLL = 0x4c4c4d4e;
  44.         const nmll_magic = view.getUint32(0, true);
  45.  
  46.         const compression_format = view.getUint8(0x05);
  47.         const is_encrypted = view.getUint32(0x1c, true);
  48.  
  49.         const key = new Uint8Array(4);
  50.         key[0] = view.getUint8(0x1C + 3);
  51.         key[1] = view.getUint8(0x1C + 2);
  52.         key[2] = view.getUint8(0x1C + 1);
  53.         key[3] = view.getUint8(0x1C + 0);
  54.         const fish = new Blowfish(key);
  55.  
  56.         const nmll = {
  57.             header_size: view.getUint32(0x08, true),
  58.             chunk_count: view.getUint32(0x0c, true),
  59.             full_length: view.getUint32(0x10, true),
  60.             comp_length: view.getUint32(0x14, true),
  61.             pointer_len: view.getUint32(0x18, true)
  62.         };
  63.  
  64.         const tmll = {
  65.             header_size: view.getUint32(0x20, true),
  66.             full_length: view.getUint32(0x24, true),
  67.             comp_length: view.getUint32(0x28, true),
  68.             chunk_count: view.getUint32(0x2c, true)
  69.         }
  70.  
  71.         /**
  72.          * READ NMLL SECTION
  73.          **/
  74.  
  75.         let ofs = 0x40;
  76.         if (is_encrypted) {
  77.             for (let i = 0; i < nmll.chunk_count; i++) {
  78.                 for (let k = ofs; k < ofs + 0x30; k += 8) {
  79.                     fish.bf_decrypt(view, k);
  80.                 }
  81.                 ofs += 0x60;
  82.             }
  83.         }
  84.  
  85.         console.log("Reading File List:");
  86.         console.log("a bebe");
  87.  
  88.         ofs = 0x40;
  89.         nmll.files = new Array(nmll.chunk_count);
  90.         for (let i = 0; i < nmll.chunk_count; i++) {
  91.             let name = "";
  92.             for (let k = 0; k < 0x20; k++) {
  93.                 let ch = view.getUint8(ofs + k);
  94.                 if (ch === 0) {
  95.                     break;
  96.                 }
  97.                 name += String.fromCharCode(ch);
  98.             }
  99.  
  100.             nmll.files[i] = {
  101.                 name: name,
  102.                 start: view.getUint32(ofs + 0x20, true),
  103.                 length: view.getUint32(ofs + 0x24, true)
  104.             };
  105.             ofs += 0x60;
  106.         }
  107.  
  108.         console.log(nmll.files);
  109.  
  110.         if (ofs % 0x800 !== 0) {
  111.             ofs = (ofs & 0xfffff800) + 0x800;
  112.         }
  113.  
  114.         // Check for empty Nbl
  115.  
  116.         if (ofs >= data.byteLength) {
  117.             return files;
  118.         }
  119.  
  120.         const nmll_len = nmll.comp_length || nmll.full_length;
  121.         let nmll_data = data.slice(ofs, ofs + nmll_len);
  122.  
  123.         if (is_encrypted) {
  124.             const rounded = Math.floor(nmll_len / 8) * 8;
  125.             const nmll_view = new DataView(nmll_data);
  126.             for (let i = 0; i < rounded; i += 8) {
  127.                 fish.bf_decrypt(nmll_view, i);
  128.             }
  129.         }
  130.  
  131.         console.log(nmll_data);
  132.         console.log("NMLL Length: 0x%s", nmll_data.byteLength.toString(16));
  133.  
  134.         if (nmll.comp_length) {
  135.             switch (compression_format) {
  136.                 case 0x00:
  137.                 case 0x40:
  138.                     nmll_data = gasetools.prs(nmll_data);
  139.                     break;
  140.                 case 0x10:
  141.                     console.log("This compression format is not supported");
  142.                     return files;
  143.                     break;
  144.                 default:
  145.                     console.log("There is another compression format?: 0x%s", compression_format.toString(16));
  146.                     break;
  147.             }
  148.         }
  149.  
  150.         console.log("NMLL Length: 0x%s", nmll_data.byteLength.toString(16));
  151.  
  152.         ofs += nmll_len;
  153.         ofs = (ofs & 0xfffff800) + 0x800;
  154.  
  155.         const pointer_table = new Array();
  156.         for (let i = 0; i < nmll.pointer_len; i += 4) {
  157.             pointer_table.push(view.getUint32(ofs + i, true));
  158.         }
  159.  
  160.         ofs += nmll.pointer_len;
  161.         if (ofs % 0x800) {
  162.             ofs = (ofs & 0xfffff800) + 0x800;
  163.         }
  164.  
  165.         const nmll_view = new DataView(nmll_data);
  166.         for (let i = 0; i < nmll.files.length; i++) {
  167.  
  168.             let f = nmll.files[i];
  169.             let start = f.start;
  170.             let end = f.start + f.length;
  171.  
  172.             let locals = [];
  173.             for (let k = 0; k < pointer_table.length; k++) {
  174.                 if (pointer_table[k] < start || pointer_table[k] >= end) {
  175.                     continue;
  176.                 }
  177.  
  178.                 let dword = nmll_view.getUint32(pointer_table[k], true);
  179.                 dword -= start;
  180.  
  181.                 if (dword < 0) {
  182.                     continue;
  183.                 }
  184.  
  185.                 nmll_view.setUint32(dword, true);
  186.             }
  187.  
  188.             let buffer = nmll_data.slice(start, end);
  189.             files[f.name] = buffer;
  190.  
  191.         }
  192.  
  193.         if (ofs >= data.byteLength) {
  194.             console.log("THIS IS THE END (NMLL ONRY)");
  195.             return files;
  196.         }
  197.  
  198.         const MAGIC_TMLL = 0x4c4c4d54;
  199.         const tmll_magic = view.getUint32(ofs, true);
  200.  
  201.         if (tmll_magic !== MAGIC_TMLL) {
  202.             console.log("NO TMLL? IS THIS RIGHT?");
  203.             return files;
  204.         }
  205.  
  206.         /**
  207.          * TMLL SECTION
  208.          **/
  209.  
  210.         console.log("STarting TMLL Section");
  211.         const tmll_start = ofs;
  212.  
  213.         ofs = tmll_start + 0x30;
  214.         if (is_encrypted) {
  215.             for (let i = 0; i < nmll.chunk_count; i++) {
  216.                 for (let k = ofs; k < ofs + 0x30; k += 8) {
  217.                     fish.bf_decrypt(view, k);
  218.                 }
  219.                 ofs += 0x60;
  220.             }
  221.         }
  222.  
  223.         console.log("Reading File List:");
  224.  
  225.         ofs = tmll_start + 0x30;
  226.         tmll.files = new Array(tmll.chunk_count);
  227.         for (let i = 0; i < nmll.chunk_count; i++) {
  228.             let name = "";
  229.             for (let k = 0; k < 0x20; k++) {
  230.                 let ch = view.getUint8(ofs + k);
  231.                 if (ch === 0) {
  232.                     break;
  233.                 }
  234.                 name += String.fromCharCode(ch);
  235.             }
  236.  
  237.             tmll.files[i] = {
  238.                 name: name,
  239.                 start: view.getUint32(ofs + 0x20, true),
  240.                 length: view.getUint32(ofs + 0x24, true)
  241.             };
  242.             ofs += 0x60;
  243.         }
  244.  
  245.         if (ofs % 0x800) {
  246.             ofs = (ofs & 0xfffff800) + 0x800;
  247.         }
  248.  
  249.         console.log(tmll.files);
  250.  
  251.         const tmll_len = tmll.comp_length || tmll.full_length;
  252.         let tmll_data = data.slice(ofs, ofs + tmll_len);
  253.  
  254.         if (tmll.comp_length) {
  255.             switch (compression_format) {
  256.                 case 0x00:
  257.                 case 0x40:
  258.                     tmll_data = gasetools.prs(tmll_data);
  259.                     break;
  260.                 case 0x10:
  261.                     console.log("This compression format is not supported");
  262.                     return files;
  263.                     break;
  264.                 default:
  265.                     console.log("0x%s", compression_format.toString(16));
  266.                     break;
  267.             }
  268.         }
  269.  
  270.         for (let i = 0; i < tmll.files.length; i++) {
  271.  
  272.             let f = tmll.files[i];
  273.             let start = f.start;
  274.             let end = f.start + f.length;
  275.             let buffer = tmll_data.slice(start, end);
  276.             files[f.name] = buffer;
  277.  
  278.         }
  279.  
  280.  
  281.         return files;
  282.  
  283.     },
  284.     prs: function(arraybuffer) {
  285.  
  286.         const self = {
  287.             ibuf: new Uint8Array(arraybuffer),
  288.             obuf: [],
  289.             iofs: 0,
  290.             bit: 0,
  291.             cmd: 0,
  292.             getByte: int_getByte,
  293.             getBit: bool_getBit
  294.         }
  295.  
  296.         let t, a, b, j, cmd;
  297.         let offset, amount, start;
  298.  
  299.         while (self.iofs < self.ibuf.length) {
  300.             cmd = self.getBit();
  301.             if (cmd) {
  302.                 self.obuf.push(self.ibuf[self.iofs]);
  303.                 self.iofs += 1;
  304.             } else {
  305.                 t = self.getBit();
  306.                 if (t) {
  307.                     a = self.getByte();
  308.                     b = self.getByte();
  309.  
  310.                     offset = ((b << 8) | a) >> 3;
  311.                     amount = a & 7;
  312.                     if (self.iofs < self.ibuf.length) {
  313.                         if (amount == 0)
  314.                             amount = self.getByte() + 1;
  315.                         else
  316.                             amount += 2;
  317.                     }
  318.                     start = self.obuf.length - 0x2000 + offset;
  319.                 } else {
  320.                     amount = 0;
  321.                     for (j = 0; j < 2; j++) {
  322.                         amount <<= 1;
  323.                         amount |= self.getBit();
  324.                     }
  325.                     offset = self.getByte();
  326.                     amount += 2;
  327.  
  328.                     start = self.obuf.length - 0x100 + offset;
  329.                 }
  330.                 for (j = 0; j < amount; j++) {
  331.                     if (start < 0)
  332.                         self.obuf.push(0);
  333.                     else if (start < self.obuf.length)
  334.                         self.obuf.push(self.obuf[start]);
  335.                     else
  336.                         self.obuf.push(0);
  337.  
  338.                     start += 1;
  339.                 }
  340.             }
  341.         } //end while
  342.  
  343.         return new Uint8Array(self.obuf).buffer;
  344.  
  345.         function int_getByte() {
  346.             let val = self.ibuf[self.iofs];
  347.             self.iofs += 1;
  348.             return parseInt(val);
  349.         }
  350.  
  351.         function bool_getBit() {
  352.             if (self.bit == 0) {
  353.                 self.cmd = self.getByte()
  354.                 self.bit = 8
  355.             }
  356.             let bit = self.cmd & 1;
  357.             self.cmd >>= 1;
  358.             self.bit -= 1;
  359.             return parseInt(bit);
  360.         }
  361.  
  362.     }
  363. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement