mirror of
https://github.com/billsonnn/nitro-converter.git
synced 2024-11-26 17:30:52 +01:00
JPEG Magic + node version check
This commit is contained in:
parent
96825fb963
commit
cd5f4a093c
3894
package-lock.json
generated
3894
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
src/Main.ts
11
src/Main.ts
@ -11,6 +11,7 @@ import { ProductDataConverter } from './converters/productdata/ProductDataConver
|
|||||||
|
|
||||||
(async () =>
|
(async () =>
|
||||||
{
|
{
|
||||||
|
checkNodeVersion();
|
||||||
const config = container.resolve(Configuration);
|
const config = container.resolve(Configuration);
|
||||||
await config.init();
|
await config.init();
|
||||||
|
|
||||||
@ -30,3 +31,13 @@ import { ProductDataConverter } from './converters/productdata/ProductDataConver
|
|||||||
await converter.convertAsync();
|
await converter.convertAsync();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
function checkNodeVersion()
|
||||||
|
{
|
||||||
|
const version = process.version.replace('v', '');
|
||||||
|
const major = version.split('.')[0];
|
||||||
|
if(parseInt(major) < 14)
|
||||||
|
{
|
||||||
|
throw new Error('Invalid node version: ' + version + ' please use >= 14');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"output.folder": "C:/nitro-converted-assets/",
|
|
||||||
"flash.client.url": "",
|
|
||||||
"furnidata.load.url": "",
|
|
||||||
"productdata.load.url": "",
|
|
||||||
"figuremap.load.url": "${flash.client.url}figuremap.xml",
|
|
||||||
"effectmap.load.url": "${flash.client.url}effectmap.xml",
|
|
||||||
"dynamic.download.pet.url": "${flash.client.url}%className%.swf",
|
|
||||||
"dynamic.download.figure.url": "${flash.client.url}%className%.swf",
|
|
||||||
"dynamic.download.effect.url": "${flash.client.url}%className%.swf",
|
|
||||||
"flash.dynamic.download.url": "",
|
|
||||||
"dynamic.download.furniture.url": "${flash.dynamic.download.url}%revision%/%className%.swf",
|
|
||||||
"external.variables.url": "https://www.habbo.com/gamedata/external_variables/1",
|
|
||||||
"external.texts.url": "${external.texts.txt}",
|
|
||||||
"convert.productdata": "1",
|
|
||||||
"convert.externaltexts": "1",
|
|
||||||
"convert.figure": "1",
|
|
||||||
"convert.effect": "1",
|
|
||||||
"convert.furniture": "1",
|
|
||||||
"convert.pet": "1"
|
|
||||||
}
|
|
@ -1,31 +1,27 @@
|
|||||||
import CustomIterator from '../utils/CustomIterator';
|
import CustomIterator from '../utils/CustomIterator';
|
||||||
import { readImagesDefineBitsLossless, readImagesJPEG, readSwfAsync } from '../utils/SwfReader';
|
import {readImagesDefineBitsLossless, readImagesJPEG3or4, readSwfAsync} from '../utils/SwfReader';
|
||||||
import { CharacterTag } from './tags/CharacterTag';
|
import {CharacterTag} from './tags/CharacterTag';
|
||||||
import { DefineBinaryDataTag } from './tags/DefineBinaryDataTag';
|
import {DefineBinaryDataTag} from './tags/DefineBinaryDataTag';
|
||||||
import { ImageTag } from './tags/ImageTag';
|
import {ImageTag} from './tags/ImageTag';
|
||||||
import { ITag } from './tags/ITag';
|
import {ITag} from './tags/ITag';
|
||||||
import { SymbolClassTag } from './tags/SymbolClassTag';
|
import {SymbolClassTag} from './tags/SymbolClassTag';
|
||||||
|
import {writeFileSync} from "fs";
|
||||||
|
|
||||||
export class HabboAssetSWF
|
export class HabboAssetSWF {
|
||||||
{
|
|
||||||
private readonly _tags: Array<ITag>;
|
private readonly _tags: Array<ITag>;
|
||||||
private _documentClass: string | null = null;
|
private _documentClass: string | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _data: string | Buffer
|
private readonly _data: string | Buffer
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
this._tags = new Array<ITag>();
|
this._tags = new Array<ITag>();
|
||||||
}
|
}
|
||||||
|
|
||||||
async setupAsync()
|
async setupAsync() {
|
||||||
{
|
|
||||||
const swf = await readSwfAsync(this._data);
|
const swf = await readSwfAsync(this._data);
|
||||||
for(const tag of swf.tags)
|
for (const tag of swf.tags) {
|
||||||
{
|
|
||||||
|
|
||||||
switch(tag.header.code)
|
switch (tag.header.code) {
|
||||||
{
|
|
||||||
case 76:
|
case 76:
|
||||||
this._tags.push(new SymbolClassTag(tag.symbols));
|
this._tags.push(new SymbolClassTag(tag.symbols));
|
||||||
break;
|
break;
|
||||||
@ -37,39 +33,57 @@ export class HabboAssetSWF
|
|||||||
console.log(tag);
|
console.log(tag);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 21:
|
case 21: {
|
||||||
console.log(tag);
|
const jpeg3 = await readImagesJPEG3or4(21, tag);
|
||||||
|
this._tags.push(new ImageTag({
|
||||||
|
code: 21,
|
||||||
|
characterID: jpeg3.characterId,
|
||||||
|
imgType: 'jpeg',
|
||||||
|
imgData: jpeg3.imageData,
|
||||||
|
bitmapWidth: jpeg3.bitmapWidth,
|
||||||
|
bitmapHeight: jpeg3.bitmapHeight
|
||||||
|
}));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 35: {
|
case 35: {
|
||||||
const jpegTag = await readImagesJPEG(35, tag);
|
const jpeg3 = await readImagesJPEG3or4(35, tag);
|
||||||
this._tags.push(new ImageTag({
|
this._tags.push(new ImageTag({
|
||||||
code: jpegTag.code,
|
code: jpeg3.code,
|
||||||
characterID: jpegTag.characterId,
|
characterID: jpeg3.characterId,
|
||||||
imgType: jpegTag.imgType,
|
imgType: jpeg3.imgType,
|
||||||
imgData: jpegTag.imgData,
|
imgData: jpeg3.imgData,
|
||||||
bitmapWidth: jpegTag.bitmapWidth,
|
bitmapWidth: jpeg3.bitmapWidth,
|
||||||
bitmapHeight: jpegTag.bitmapHeight
|
bitmapHeight: jpeg3.bitmapHeight
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 36: {
|
case 36: {
|
||||||
const pngTag: any = await readImagesDefineBitsLossless(tag);
|
const pngTagLossLess2: any = await readImagesDefineBitsLossless(tag);
|
||||||
this._tags.push(new ImageTag({
|
this._tags.push(new ImageTag({
|
||||||
code: pngTag.code,
|
code: pngTagLossLess2.code,
|
||||||
characterID: pngTag.characterId,
|
characterID: pngTagLossLess2.characterId,
|
||||||
imgType: pngTag.imgType,
|
imgType: pngTagLossLess2.imgType,
|
||||||
imgData: pngTag.imgData,
|
imgData: pngTagLossLess2.imgData,
|
||||||
bitmapWidth: pngTag.bitmapWidth,
|
bitmapWidth: pngTagLossLess2.bitmapWidth,
|
||||||
bitmapHeight: pngTag.bitmapHeight
|
bitmapHeight: pngTagLossLess2.bitmapHeight
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 20:
|
case 20: {
|
||||||
console.log(tag);
|
const pngTagLossless: any = await readImagesDefineBitsLossless(tag);
|
||||||
|
this._tags.push(new ImageTag({
|
||||||
|
code: pngTagLossless.code,
|
||||||
|
characterID: pngTagLossless.characterId,
|
||||||
|
imgType: pngTagLossless.imgType,
|
||||||
|
imgData: pngTagLossless.imgData,
|
||||||
|
bitmapWidth: pngTagLossless.bitmapWidth,
|
||||||
|
bitmapHeight: pngTagLossless.bitmapHeight
|
||||||
|
}));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 90:
|
case 90:
|
||||||
console.log(tag);
|
console.log(tag);
|
||||||
@ -84,47 +98,37 @@ export class HabboAssetSWF
|
|||||||
this.assignClassesToSymbols();
|
this.assignClassesToSymbols();
|
||||||
}
|
}
|
||||||
|
|
||||||
public imageTags(): Array<ImageTag>
|
public imageTags(): Array<ImageTag> {
|
||||||
{
|
|
||||||
return this._tags.filter((tag: ITag) => tag instanceof ImageTag).map(x => x as ImageTag);
|
return this._tags.filter((tag: ITag) => tag instanceof ImageTag).map(x => x as ImageTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public symbolTags(): Array<SymbolClassTag>
|
public symbolTags(): Array<SymbolClassTag> {
|
||||||
{
|
|
||||||
return this._tags.filter((tag: ITag) => tag instanceof SymbolClassTag).map(x => x as SymbolClassTag);
|
return this._tags.filter((tag: ITag) => tag instanceof SymbolClassTag).map(x => x as SymbolClassTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
private binaryTags(): Array<DefineBinaryDataTag>
|
private binaryTags(): Array<DefineBinaryDataTag> {
|
||||||
{
|
|
||||||
return this._tags.filter((tag: ITag) => tag instanceof DefineBinaryDataTag).map(x => x as DefineBinaryDataTag);
|
return this._tags.filter((tag: ITag) => tag instanceof DefineBinaryDataTag).map(x => x as DefineBinaryDataTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
private assignClassesToSymbols()
|
private assignClassesToSymbols() {
|
||||||
{
|
|
||||||
const classes: Map<number, string> = new Map();
|
const classes: Map<number, string> = new Map();
|
||||||
|
|
||||||
let iterator: CustomIterator<ITag> = new CustomIterator(this._tags);
|
let iterator: CustomIterator<ITag> = new CustomIterator(this._tags);
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while(true)
|
while (true) {
|
||||||
{
|
|
||||||
let t: ITag;
|
let t: ITag;
|
||||||
|
|
||||||
do
|
do {
|
||||||
{
|
if (!iterator.hasNext()) {
|
||||||
if(!iterator.hasNext())
|
|
||||||
{
|
|
||||||
iterator = new CustomIterator(this._tags);
|
iterator = new CustomIterator(this._tags);
|
||||||
|
|
||||||
while(iterator.hasNext())
|
while (iterator.hasNext()) {
|
||||||
{
|
|
||||||
t = iterator.next();
|
t = iterator.next();
|
||||||
if(t instanceof CharacterTag)
|
if (t instanceof CharacterTag) {
|
||||||
{
|
|
||||||
const ct = t as CharacterTag;
|
const ct = t as CharacterTag;
|
||||||
|
|
||||||
if(classes.has(ct.characterId))
|
if (classes.has(ct.characterId)) {
|
||||||
{
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ct.className = classes.get(ct.characterId);
|
ct.className = classes.get(ct.characterId);
|
||||||
}
|
}
|
||||||
@ -135,46 +139,37 @@ export class HabboAssetSWF
|
|||||||
}
|
}
|
||||||
|
|
||||||
t = iterator.next();
|
t = iterator.next();
|
||||||
} while(!(t instanceof SymbolClassTag));
|
} while (!(t instanceof SymbolClassTag));
|
||||||
|
|
||||||
const sct = t as SymbolClassTag;
|
const sct = t as SymbolClassTag;
|
||||||
|
|
||||||
for(let i = 0; i < sct.tags.length; ++i)
|
for (let i = 0; i < sct.tags.length; ++i) {
|
||||||
{
|
if (!classes.has(sct.tags[i]) && !Array.from(classes.values()).includes(sct.names[i])) {
|
||||||
if(!classes.has(sct.tags[i]) && !Array.from(classes.values()).includes(sct.names[i]))
|
|
||||||
{
|
|
||||||
classes.set(sct.tags[i], sct.names[i]);
|
classes.set(sct.tags[i], sct.names[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getBinaryTagByName(name: string): DefineBinaryDataTag | null
|
public getBinaryTagByName(name: string): DefineBinaryDataTag | null {
|
||||||
{
|
|
||||||
const streamTag = this.binaryTags()
|
const streamTag = this.binaryTags()
|
||||||
.filter(tag => tag.className === name)[0];
|
.filter(tag => tag.className === name)[0];
|
||||||
|
|
||||||
if(streamTag === undefined) return null;
|
if (streamTag === undefined) return null;
|
||||||
|
|
||||||
return streamTag;
|
return streamTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFullClassName(type: string, documentNameTwice: boolean): string
|
public getFullClassName(type: string, documentNameTwice: boolean): string {
|
||||||
{
|
|
||||||
return this.getFullClassNameSnake(type, documentNameTwice, false);
|
return this.getFullClassNameSnake(type, documentNameTwice, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFullClassNameSnake(type: string, documentNameTwice: boolean, snakeCase: boolean): string
|
public getFullClassNameSnake(type: string, documentNameTwice: boolean, snakeCase: boolean): string {
|
||||||
{
|
|
||||||
let result: string = this.getDocumentClass() + '_';
|
let result: string = this.getDocumentClass() + '_';
|
||||||
if(documentNameTwice)
|
if (documentNameTwice) {
|
||||||
{
|
if (snakeCase) {
|
||||||
if(snakeCase)
|
|
||||||
{
|
|
||||||
//result += CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, this.swf.getDocumentClass()) + "_";
|
//result += CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, this.swf.getDocumentClass()) + "_";
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
result += this.getDocumentClass() + '_';
|
result += this.getDocumentClass() + '_';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,32 +177,26 @@ export class HabboAssetSWF
|
|||||||
return result + type;
|
return result + type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDocumentClass(): string
|
public getDocumentClass(): string {
|
||||||
{
|
if (this._documentClass !== null) return this._documentClass;
|
||||||
if(this._documentClass !== null) return this._documentClass;
|
|
||||||
|
|
||||||
const iterator: CustomIterator<ITag> = new CustomIterator(this._tags);
|
const iterator: CustomIterator<ITag> = new CustomIterator(this._tags);
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while(true)
|
while (true) {
|
||||||
{
|
|
||||||
let t: ITag;
|
let t: ITag;
|
||||||
do
|
do {
|
||||||
{
|
if (!iterator.hasNext()) {
|
||||||
if(!iterator.hasNext())
|
|
||||||
{
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
t = iterator.next();
|
t = iterator.next();
|
||||||
} while(!(t instanceof SymbolClassTag));
|
} while (!(t instanceof SymbolClassTag));
|
||||||
|
|
||||||
const sc = t as SymbolClassTag;
|
const sc = t as SymbolClassTag;
|
||||||
|
|
||||||
for(let i = 0; i < sc.tags.length; ++i)
|
for (let i = 0; i < sc.tags.length; ++i) {
|
||||||
{
|
if (sc.tags[i] == 0) {
|
||||||
if(sc.tags[i] == 0)
|
|
||||||
{
|
|
||||||
this._documentClass = sc.names[i];
|
this._documentClass = sc.names[i];
|
||||||
return this._documentClass;
|
return this._documentClass;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import {writeFileSync} from "fs";
|
||||||
|
|
||||||
const SWFReader = require('@gizeta/swf-reader');
|
const SWFReader = require('@gizeta/swf-reader');
|
||||||
|
|
||||||
const _encoder = require('png-stream/encoder');
|
const _encoder = require('png-stream/encoder');
|
||||||
@ -98,14 +100,17 @@ export function readSwfAsync(data: string | Buffer): Promise<any>
|
|||||||
|
|
||||||
const pngMagic = Buffer.from('0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A'.split(' ').map(Number));
|
const pngMagic = Buffer.from('0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A'.split(' ').map(Number));
|
||||||
const gifMagic = Buffer.from('0x47 0x49 0x46 0x38 0x39 0x61'.split(' ').map(Number));
|
const gifMagic = Buffer.from('0x47 0x49 0x46 0x38 0x39 0x61'.split(' ').map(Number));
|
||||||
|
const jpegMagic = Buffer.from('0xFF 0xD8'.split(' ').map(Number));
|
||||||
const recognizeHeader = function recognizeHeader(buffer: Buffer)
|
const recognizeHeader = function recognizeHeader(buffer: Buffer)
|
||||||
{
|
{
|
||||||
if(pngMagic.equals(buffer.slice(0, pngMagic.length))) return 'png';
|
if(pngMagic.equals(buffer.slice(0, pngMagic.length))) return 'png';
|
||||||
if(gifMagic.equals(buffer.slice(0, gifMagic.length))) return 'gif';
|
if(gifMagic.equals(buffer.slice(0, gifMagic.length))) return 'gif';
|
||||||
return 'jpeg';
|
if(jpegMagic.equals(buffer.slice(0, jpegMagic.length))) return 'jpeg';
|
||||||
|
|
||||||
|
throw new Error('unknown format: ' + buffer.slice(0, 8));
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function readImagesJPEG(code: number, tagData: any): Promise<any>
|
export async function readImagesJPEG3or4(code: number, tagData: any): Promise<any>
|
||||||
{
|
{
|
||||||
const characterId = tagData.characterId,
|
const characterId = tagData.characterId,
|
||||||
imageData = tagData.imageData;
|
imageData = tagData.imageData;
|
||||||
@ -141,7 +146,7 @@ export async function readImagesJPEG(code: number, tagData: any): Promise<any>
|
|||||||
other two zlib.unzip call happens at sites that an empty uncompressed Buffer
|
other two zlib.unzip call happens at sites that an empty uncompressed Buffer
|
||||||
does not make sense. So I think the current fix is good enough.
|
does not make sense. So I think the current fix is good enough.
|
||||||
*/
|
*/
|
||||||
if(bitmapAlphaData.length > 0)
|
if(bitmapAlphaData && bitmapAlphaData.length > 0)
|
||||||
{
|
{
|
||||||
return reject(new Error(err));
|
return reject(new Error(err));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user