commit 9b6983e5563708c5eb6cc64876ff01877b0bb163 Author: KyMAN <0kyman0@gmail.com> Date: Mon Jul 20 07:23:37 2026 +0200 #wip: SFFModel. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..316581d --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/Data +/Public/data +*.[Ss]ecrets.* +*.[Ss]ecret.* +*.[Ss]ecrets +*.[Ss]ecret +*.deleted \ No newline at end of file diff --git a/Public/ecma/Models/BinaryStructureModel.ecma.js b/Public/ecma/Models/BinaryStructureModel.ecma.js new file mode 100644 index 0000000..664a2b7 --- /dev/null +++ b/Public/ecma/Models/BinaryStructureModel.ecma.js @@ -0,0 +1,65 @@ +"use strict"; + +import {Common} from "http://localhost:18000/Public/ecma/Utils/Common.ecma.js"; +import {Check} from "http://localhost:18000/Public/ecma/Utils/Checks.ecma.js"; + +/** + * @class BinaryStructureModel + * @constructor + * @param {!string} type + * @param {!string} name + * @param {!number} from + * @param {?number} size + * @param {!Array.} [childs = []] + * @returns {void} + * @access public + * @static + */ +export const BinaryStructureModel = (function(){ + + /** + * @constructs BinaryStructureModel + * @param {!string} type + * @param {!string} name + * @param {!number} from + * @param {?number} size + * @param {!Array.} [childs = []] + * @returns {void} + * @access private + * @static + */ + const BinaryStructureModel = function(type, name, from, size, childs = []){ + + /** @type {BinaryStructureModel} */ + const self = this; + + /** @type {string} */ + this.name = name; + /** @type {string} */ + this.type = type; + /** @type {number} */ + this.from = from; + /** @type {number|null} */ + this.size = null; + /** @type {Array.} */ + this.childs = childs || []; + /** @type {number|null} */ + this.next = null; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + if(Check.is_array(size)) + self.next = size[0]; + else if(Check.is_number(size)) + self.size = size; + }; + + constructor(); + + }; + + return BinaryStructureModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/SFFv1Model.ecma.js b/Public/ecma/Models/SFFv1Model.ecma.js new file mode 100644 index 0000000..96bda8b --- /dev/null +++ b/Public/ecma/Models/SFFv1Model.ecma.js @@ -0,0 +1,177 @@ +"use strict"; + +import {Common} from "http://localhost:18000/Public/ecma/Utils/Common.ecma.js"; +import {Tools} from "../Utils/Tools.ecma.js"; + +export const SFFPCXModel = (function(){ + + const SFFPCXModel = function(pcx, palette_size = 0){ + + const self = this; + + this.id = null; + this.version = null; + this.encoding = null; + this.bit = null; + this.x = null; + this.y = null; + this.width = null; + this.height = null; + this.horizontal = null; + this.vertical = null; + this.color_map = null; + this.reserved = null; + this.planes = null; + this.bytes_per_line = null; + this.information = null; + this.filler = null; + this.data = null; + this.ok = null; + this.palette = null; + + const constructor = () => { + + Object.entries(Tools.load_binary(pcx, [ + ["id", "integer", 1], + ["version", "integer", 1], + ["encoding", "integer", 1], + ["bit", "integer", 1], + ["x", "integer", 2], + ["y", "integer", 2], + ["width", "integer", 2], + ["height", "integer", 2], + ["horizontal", "integer", 2], + ["vertical", "integer", 2], + ["color_map", (bytes, _) => bytes.reduce((map, byte, j) => { + + const k = j / 3 >> 0; + + (map[k] || (map[k] = []))[j % 3] = byte; + + return map; + }), 48], + ["reserved", "integer", 1], + ["planes", "integer", 1], + ["bytes_per_line", "integer", 2], + ["information", "integer", 2], + ["filler", "bytes", 58], + ["data", "bytes", object => pcx.length - 128 - palette_size - (palette_size ? 1 : 0)], + ["ok", (bytes, _) => !bytes.length || bytes[0] == 12, palette_size ? 1 : 0], + ["palette", "bytes", palette_size] + ])).forEach(([key, value]) => { + self[key] = value; + }); + + }; + + constructor(); + + }; + + return SFFPCXModel; +})(); + +export const SFFv1ImageModel = (function(){ + + const SFFv1ImageModel = function(version, data){ + + const self = this; + + this.next = null; + this.length = null; + this.x = null; + this.y = null; + this.group = null; + this.i = null; + this.shared_flag = null; + this.comments = null; + this.image = null; + + const constructor = () => { + + Object.entries(Tools.load_binary(data, [ + ["next", "integer", 4], + ["length", "integer", 4], + ["x", "integer", 2], + ["y", "integer", 2], + ["group", "integer", 2], + ["i", "integer", 2], + ["shared_flag", "boolean", 1], + ["comments", "string", 15], + ["image", "bytes", object => object.length] + ])).forEach(([key, value]) => { + if(key == "image"){ + self[key] = new SFFPCXModel(value, self.shared_flag ? 0 : 768); + }else + self[key] = value; + }); + + }; + + constructor(); + + }; + + return SFFv1ImageModel; +})(); + +export const SFFv1Model = (function(){ + + const SFFv1Model = function(sff, callback = null){ + + const self = this; + + this.signature = ""; + this.version = []; + this.groups = {}; + this.images = []; + this.next = null; + this.offset_palette = null; + this.shared_palette = null; + this.comments = ""; + + const constructor = () => { + + let images_l, + groups_l, + offset; + + Object.entries(Tools.load_binary(sff, [ + ["signature", "string", 12], + ["version", "bytes", 4], + ["groups", "integer", 4], + ["images", "integer", 4], + ["next", "integer", 4], + ["offset_palette", "integer", 4], + ["shared_palette", "boolean", 4], + ["comments", "string", object => object.next - 36] + ])).forEach(([key, value]) => { + if(key == "images") + images_l = value; + else if(key == "groups") + groups_l = value; + else + self[key] = value; + }); + + offset = self.next; + + while(self.images.length < images_l){ + + const image = new SFFImageModel(self.version, sff.slice(offset)); + + self.images.push(image); + offset = image.next; + + }; + + Common.execute(callback, self); + + }; + + constructor(); + + }; + + return SFFv1Model; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/SFFv2Model.ecma.js b/Public/ecma/Models/SFFv2Model.ecma.js new file mode 100644 index 0000000..3c9fe1e --- /dev/null +++ b/Public/ecma/Models/SFFv2Model.ecma.js @@ -0,0 +1,153 @@ +"use strict"; + +import {Common} from "http://localhost:18000/Public/ecma/Utils/Common.ecma.js"; +import {Tools} from "../Utils/Tools.ecma.js"; + +export const SFFv2PaletteModel = (function(){ + + const SFFv2PaletteModel = function(data, sff){ + + const self = this; + + this.group = null; + this.item = null; + this.columns = null; + this.link = null; + this.data_offset = null; + this.data_length = null; + this.palette = null; + + const constructor = () => { + + Object.entries(Tools.load_binary(data, [ + ["group", "integer", 2], + ["item", "integer", 2], + ["columns", "integer", 2], + ["link", "integer", 2], + ["data_offset", "integer", 4], + ["data_length", "integer", 4] + ])).forEach(([key, value]) => { + self[key] = value; + }); + + if(self.data_length > 0) + self.palette = sff.slice(self.data_offset, self.data_offset + self.data_length); + + }; + + constructor(); + }; + + return SFFv2PaletteModel; +})(); + +export const SFFv2SpriteModel = (function(){ + + const SFFv2SpriteModel = function(data, sff){ + + const self = this; + + this.group = null; + this.item = null; + this.width = null; + this.height = null; + this.x = null; + this.y = null; + this.link = null; + this.format = null; + this.depth = null; + this.data_offset = null; + this.data_length = null; + this.palette_index = null; + this.flags = null; + this.data = null; + + const constructor = () => { + + Object.entries(Tools.load_binary(data, [ + ["group", "integer", 2], + ["item", "integer", 2], + ["width", "integer", 2], + ["height", "integer", 2], + ["x", "integer", 2], + ["y", "integer", 2], + ["link", "integer", 2], + ["format", "integer", 1], + ["depth", "integer", 1], + ["data_offset", "integer", 4], + ["data_length", "integer", 4], + ["palette_index", "integer", 2], + ["flags", "integer", 2] + ])).forEach(([key, value]) => { + self[key] = value; + }); + + if(self.data_length > 0) + self.data = sff.slice(self.data_offset, self.data_offset + self.data_length); + + }; + + constructor(); + }; + + return SFFv2SpriteModel; +})(); + +export const SFFv2Model = (function(){ + + const SFFv2Model = function(sff, callback = null){ + + const self = this; + + this.signature = ""; + this.version = []; + this.sprites = []; + this.palettes = []; + this.sprite_offset = null; + this.sprite_count = null; + this.palette_offset = null; + this.palette_count = null; + + const constructor = () => { + + Object.entries(Tools.load_binary(sff.slice(0, 512), [ + ["signature", "string", 12], + ["version", "bytes", 4], + ["reserved1", "bytes", 4], + ["reserved2", "bytes", 4], + ["compat_ver", "bytes", 4], + ["reserved3", "bytes", 4], + ["sprite_offset", "integer", 4], + ["sprite_count", "integer", 4], + ["palette_offset", "integer", 4], + ["palette_count", "integer", 4], + ["literal_data_offset", "integer", 4], + ["literal_data_length", "integer", 4], + ["translated_data_offset", "integer", 4], + ["translated_data_length", "integer", 4], + ["filler", "bytes", 448] + ])).forEach(([key, value]) => { + if(self[key] !== undefined) + self[key] = value; + }); + + while(self.sprite_offset < self.sprite_count){ + self.sprites.push(new SFFv2SpriteModel(sff.slice(self.sprite_offset, self.sprite_offset + 16), sff)); + self.sprite_offset += 16; + }; + + while(self.palette_offset < self.palette_count){ + self.palettes.push(new SFFv2PaletteModel(sff.slice(self.palette_offset, self.palette_offset + 28), sff)); + self.palette_offset += 28; + }; + + Common.call(callback, self); + + }; + + constructor(); + + }; + + return SFFv2Model; +})(); \ No newline at end of file diff --git a/Public/ecma/Utils/Tools.ecma.js b/Public/ecma/Utils/Tools.ecma.js new file mode 100644 index 0000000..e59658b --- /dev/null +++ b/Public/ecma/Utils/Tools.ecma.js @@ -0,0 +1,79 @@ +"use strict"; + +import {BinaryStructureModel} from "../Models/BinaryStructureModel.ecma.js"; +import {Check} from "http://localhost:18000/Public/ecma/Utils/Checks.ecma.js"; + +/** + * @class Tools + * @constructor + * @returns {void} + * @access public + * @static + */ +export const Tools = (function(){ + + /** + * @callback load_binary_type_callback + * @param {!Uint8Array|Array.} data + * @param {!Object.} object + * @returns {any|null} + */ + + /** + * @callback load_binary_size_callback + * @param {!Object.} object + * @returns {any|null} + */ + + /** + * @constructs Tools + * @returns {void} + * @access private + * @static + */ + const Tools = function(){}; + + /** + * @param {!Uint8Array|Array.} data + * @param {!Array.>} structure + * @returns {Object.} + * @access public + * @static + */ + Tools.load_binary = (data, structure) => { + + /** @type {number} */ + let i = 0; + + return structure.reduce((object, [name, type, size]) => { + + if(Check.is_function(size)) + size = size(object); + + if(Check.is_function(type)) + object[name] = type(data.slice(i, i + size), object); + else{ + + /** @type {any} */ + const value = data.slice(i, i + size); + + object[name] = ( + type == "string" ? String.fromCharCode(...value).replace(/\0/g, "") : + type == "integer" ? value.reduce((accurate, byte, j) => accurate | (byte << j * 8), 0) : + type == "boolean" ? !!value.reduce((accurate, byte, j) => accurate | (byte << j * 8), 0) : + type == "bytes" ? Array.from(value) : + value); + + if(type == "integer" && size < 4 && object[name] >> size * 8 - 1) + object[name] -= 1 << size * 8; + + }; + + i += size; + + return object; + }, {}); + }; + + return Tools; +})(); \ No newline at end of file diff --git a/Public/index.html b/Public/index.html new file mode 100644 index 0000000..e69de29