mirror of
https://github.com/billsonnn/nitro-converter.git
synced 2024-11-29 18:50:51 +01:00
Further fixes
This commit is contained in:
parent
cd5f4a093c
commit
d66a145e14
20
package-lock.json
generated
20
package-lock.json
generated
@ -69,14 +69,6 @@
|
|||||||
"strip-json-comments": "^3.1.1"
|
"strip-json-comments": "^3.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@gizeta/swf-reader": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@gizeta/swf-reader/-/swf-reader-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-34Huyh7J7miWax2Tbd/iH5Hp3IM=",
|
|
||||||
"requires": {
|
|
||||||
"lzma-purejs": "~0.9.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@jimp/bmp": {
|
"@jimp/bmp": {
|
||||||
"version": "0.16.1",
|
"version": "0.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.16.1.tgz",
|
||||||
@ -2187,11 +2179,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pako": {
|
|
||||||
"version": "1.0.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
|
||||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
|
||||||
},
|
|
||||||
"parent-module": {
|
"parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@ -3041,6 +3028,13 @@
|
|||||||
"integrity": "sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==",
|
"integrity": "sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"pako": "^1.0.5"
|
"pako": "^1.0.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"pako": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"util-deprecate": {
|
"util-deprecate": {
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gizeta/swf-reader": "^1.0.0",
|
|
||||||
"bytebuffer": "^5.0.1",
|
"bytebuffer": "^5.0.1",
|
||||||
"concat-frames": "^1.0.3",
|
"concat-frames": "^1.0.3",
|
||||||
"free-tex-packer-core": "^0.3.2",
|
"free-tex-packer-core": "^0.3.2",
|
||||||
"jimp": "^0.16.1",
|
"jimp": "^0.16.1",
|
||||||
"jpg-stream": "^1.1.2",
|
"jpg-stream": "^1.1.2",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
|
"lzma-purejs": "^0.9.3",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"node-gzip": "^1.1.2",
|
"node-gzip": "^1.1.2",
|
||||||
"ora": "^5.3.0",
|
"ora": "^5.3.0",
|
||||||
|
450
src/swf-reader/index.js
Normal file
450
src/swf-reader/index.js
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
/**
|
||||||
|
* Simple module for reading SWF properties
|
||||||
|
*
|
||||||
|
* (c) 2014 Rafael Leal Dias <rafaeldias.c at gmail dot com>
|
||||||
|
* MIT LICENCE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
var fs = require('fs')
|
||||||
|
, zlib = require('zlib')
|
||||||
|
, lzma = require('lzma-purejs')
|
||||||
|
, Stream = require('stream')
|
||||||
|
, SWFBuffer = require('./lib/swf-buffer')
|
||||||
|
, SWFTags = require('./lib/swf-tags')
|
||||||
|
, SWFReader = exports;
|
||||||
|
|
||||||
|
function readSWFTags(buff, swf) {
|
||||||
|
var tags = []
|
||||||
|
, tag
|
||||||
|
, tagHeader
|
||||||
|
, flag
|
||||||
|
, l
|
||||||
|
, sc
|
||||||
|
, fc;
|
||||||
|
|
||||||
|
/* Reads TagCodeAndLength from Tag's RECORDHEADER */
|
||||||
|
while( (tagHeader = buff.readTagCodeAndLength()) ) {
|
||||||
|
tag = {
|
||||||
|
header : tagHeader
|
||||||
|
};
|
||||||
|
switch( tagHeader.code ) {
|
||||||
|
case SWFTags.FileAttributes :
|
||||||
|
flag = buff.readUIntLE(32);
|
||||||
|
fileAttrs = {}
|
||||||
|
|
||||||
|
fileAttrs.useNetwork = tag.useNetwork = !!(flag & 0x1);
|
||||||
|
fileAttrs.as3 = tag.as3 = !!(flag & 0x8);
|
||||||
|
fileAttrs.hasMetaData = tag.hasMetaData = !!(flag & 0x10);
|
||||||
|
fileAttrs.useGPU = tag.useGPU = !!(flag & 0x20);
|
||||||
|
fileAttrs.useDirectBit = tag.useDirectBlit = !!(flag & 0x40);
|
||||||
|
|
||||||
|
swf.fileAttributes = fileAttrs;
|
||||||
|
break;
|
||||||
|
case SWFTags.Metadata :
|
||||||
|
swf.metadata = tag.metadata = buff.readString()
|
||||||
|
break;
|
||||||
|
case SWFTags.SetBackgroundColor :
|
||||||
|
tag.RGB = buff.readRGB();
|
||||||
|
swf.backgroundColor = '#' + (tag.RGB[0]*65536 + tag.RGB[1]*256 + tag.RGB[0]).toString(16);
|
||||||
|
break;
|
||||||
|
case SWFTags.Protect :
|
||||||
|
swf.protect = tagHeader.length && buff.readString();
|
||||||
|
break;
|
||||||
|
case SWFTags.DefineSceneAndFrameLabelData :
|
||||||
|
sc = tag.sceneCount = buff.readEncodedU32();
|
||||||
|
tag.scenes = [];
|
||||||
|
|
||||||
|
while (sc--)
|
||||||
|
tag.scenes.push({
|
||||||
|
offset : buff.readEncodedU32(),
|
||||||
|
name : buff.readString()
|
||||||
|
});
|
||||||
|
|
||||||
|
fc = tag.frameLabelCount = buff.readEncodedU32();
|
||||||
|
tag.labels = [];
|
||||||
|
|
||||||
|
while (fc--)
|
||||||
|
tag.labels.push({
|
||||||
|
frameNum : buff.readEncodedU32(),
|
||||||
|
frameLabel : buff.readString()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
/**
|
||||||
|
* DefineShape4 extends the capabilities of
|
||||||
|
* DefineShape3 by using a new line style
|
||||||
|
* record in the shape
|
||||||
|
*/
|
||||||
|
//case SWFTags.DefineShape4 :
|
||||||
|
// /* id for this character */
|
||||||
|
// tag.ShapeId = buff.readUIntLE(16);
|
||||||
|
// /* bounds of the shape */
|
||||||
|
// tag.ShapeBounds = buff.readRect();
|
||||||
|
// /* bounds of the shape, excluding the strokes */
|
||||||
|
// tag.EdgeBounds = buff.readRect();
|
||||||
|
// /* reserved, must be 0 */
|
||||||
|
// if (0 !== buff.readBits(5))
|
||||||
|
// throw new Error('Reserved bit used.');
|
||||||
|
// /* if 1, use fill winding. >= SWF 10 */
|
||||||
|
// if (swf.version >= 10)
|
||||||
|
// tag.UsesFillWindingRule = buff.readBits(1);
|
||||||
|
// /**
|
||||||
|
// * if 1, shape contains at least one
|
||||||
|
// * non-scaling stroke.
|
||||||
|
// */
|
||||||
|
// tag.UsesNonScallingStrokes = buff.readBits(1);
|
||||||
|
// /**
|
||||||
|
// * if 1, shape contains at least one
|
||||||
|
// * scaling stroke
|
||||||
|
// */
|
||||||
|
// tag.UsesScalingStrokes = buff.readBits(1);
|
||||||
|
// tag.shapes = buff.readShapeWithStyle();
|
||||||
|
// break;
|
||||||
|
case SWFTags.FrameLabel :
|
||||||
|
tag.name = buff.readString()
|
||||||
|
l = Buffer.byteLength(tag.name);
|
||||||
|
/* check if it's an named anchor */
|
||||||
|
if (l & (tagHeader.length - 1) != l)
|
||||||
|
tag.anchor = buff.readUInt8();
|
||||||
|
break;
|
||||||
|
case SWFTags.DefineSprite :
|
||||||
|
tag.SpriteID = buff.readUIntLE(16);
|
||||||
|
tag.FrameCount = buff.readUIntLE(16);
|
||||||
|
tag.ControlTags = readSWFTags(buff, swf);
|
||||||
|
break;
|
||||||
|
case SWFTags.ExportAssets :
|
||||||
|
tag.count = buff.readUIntLE(16);
|
||||||
|
tag.assets = [];
|
||||||
|
|
||||||
|
l = 0;
|
||||||
|
|
||||||
|
while (l++ < tag.count)
|
||||||
|
tag.assets.push({
|
||||||
|
id : buff.readUIntLE(16),
|
||||||
|
name : buff.readString()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SWFTags.ImportAssets :
|
||||||
|
/**
|
||||||
|
* URL where the source SWF file can be found
|
||||||
|
*/
|
||||||
|
tag.url = buff.readString();
|
||||||
|
/**
|
||||||
|
* Number of assets to import
|
||||||
|
*/
|
||||||
|
tag.count = buff.readUIntLE(16);
|
||||||
|
tag.assets = [];
|
||||||
|
|
||||||
|
l = 0;
|
||||||
|
|
||||||
|
while (l++ < tag.count)
|
||||||
|
tag.assets.push({
|
||||||
|
/**
|
||||||
|
* Character ID for the l-th item
|
||||||
|
* in importing SWF file
|
||||||
|
*/
|
||||||
|
id : buff.readUIntLE(16),
|
||||||
|
/**
|
||||||
|
* Identifies for the l-th
|
||||||
|
* imported character
|
||||||
|
*/
|
||||||
|
name : buff.readString()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SWFTags.ImportAssets2 :
|
||||||
|
tag.url = buff.readString();
|
||||||
|
|
||||||
|
if ( !(1 === buff.readUInt8() && 0 === buff.readUInt8()) ) {
|
||||||
|
throw new Error('Reserved bits for ImportAssets2 used');
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.count = buff.readUIntLE(16);
|
||||||
|
tag.assets = [];
|
||||||
|
|
||||||
|
l = 0;
|
||||||
|
|
||||||
|
while (l++ < tag.count)
|
||||||
|
tag.assets({
|
||||||
|
id : buff.readUIntLE(16),
|
||||||
|
name : buff.readString()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SWFTags.EnableDebbuger :
|
||||||
|
tag.password = buff.readString()
|
||||||
|
break;
|
||||||
|
case SWFTags.EnableDebugger2 :
|
||||||
|
if (0 !== buff.readUIntLE(16)) {
|
||||||
|
//throw new Error('Reserved bit for EnableDebugger2 used.');
|
||||||
|
}
|
||||||
|
tag.password = buff.readString()
|
||||||
|
break;
|
||||||
|
case SWFTags.ScriptLimits :
|
||||||
|
/**
|
||||||
|
* Maximum recursion Depth
|
||||||
|
*/
|
||||||
|
tag.maxRecursionDepth = buff.readUIntLE(16);
|
||||||
|
/**
|
||||||
|
* Maximum ActionScript processing time before script
|
||||||
|
* stuck dialog box displays
|
||||||
|
*/
|
||||||
|
tag.scriptTimeoutSeconds = buff.readUIntLE(16);
|
||||||
|
break;
|
||||||
|
case SWFTags.SymbolClass :
|
||||||
|
tag.numSymbols = buff.readUIntLE(16);
|
||||||
|
tag.symbols = [];
|
||||||
|
|
||||||
|
l = 0;
|
||||||
|
|
||||||
|
while (l++ < tag.numSymbols)
|
||||||
|
tag.symbols.push({
|
||||||
|
id : buff.readUIntLE(16),
|
||||||
|
name : buff.readString()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case SWFTags.DefineScalingGrid :
|
||||||
|
tag.characterId = buff.readUIntLE(16);
|
||||||
|
tag.splitter = buff.readRect();
|
||||||
|
break;
|
||||||
|
case SWFTags.setTabIndex :
|
||||||
|
tag.depth = buff.readUIntLE(16);
|
||||||
|
tag.tabIndex = buff.readUIntLE(16);
|
||||||
|
break;
|
||||||
|
case SWFTags.JPEGTables:
|
||||||
|
tag.jpegData = buff.buffer.slice(buff.pointer, buff.pointer + tagHeader.length);
|
||||||
|
buff.pointer += tagHeader.length;
|
||||||
|
break;
|
||||||
|
case SWFTags.DefineBits:
|
||||||
|
tag.characterId = buff.readUIntLE(16);
|
||||||
|
tag.jpegData = buff.buffer.slice(buff.pointer, buff.pointer + tagHeader.length - 2);
|
||||||
|
buff.pointer += tagHeader.length - 2;
|
||||||
|
break;
|
||||||
|
case SWFTags.DefineBitsJPEG2:
|
||||||
|
tag.characterId = buff.readUIntLE(16);
|
||||||
|
tag.imageData = buff.buffer.slice(buff.pointer, buff.pointer + tagHeader.length - 2);
|
||||||
|
buff.pointer += tagHeader.length - 2;
|
||||||
|
break;
|
||||||
|
case SWFTags.DefineBitsJPEG3:
|
||||||
|
tag.characterId = buff.readUIntLE(16);
|
||||||
|
var alphaDataOffset = buff.readUIntLE(32);
|
||||||
|
tag.imageData = buff.buffer.slice(buff.pointer, buff.pointer + alphaDataOffset);
|
||||||
|
buff.pointer += alphaDataOffset;
|
||||||
|
var restLength = tagHeader.length - 6 - alphaDataOffset;
|
||||||
|
tag.bitmapAlphaData = buff.buffer.slice(buff.pointer, buff.pointer + restLength);
|
||||||
|
buff.pointer += restLength;
|
||||||
|
break;
|
||||||
|
case SWFTags.DefineBitsJPEG4:
|
||||||
|
tag.characterId = buff.readUIntLE(16);
|
||||||
|
var alphaDataOffset = buff.readUIntLE(32);
|
||||||
|
tag.deblockParam = buff.readUIntLE(16);
|
||||||
|
tag.imageData = buff.buffer.slice(buff.pointer, buff.pointer + alphaDataOffset);
|
||||||
|
buff.pointer += alphaDataOffset;
|
||||||
|
var restLength = tagHeader.length - 8 - alphaDataOffset;
|
||||||
|
tag.bitmapAlphaData = buff.buffer.slice(buff.pointer, buff.pointer + restLength);
|
||||||
|
buff.pointer += restLength;
|
||||||
|
break;
|
||||||
|
case SWFTags.DefineBitsLossless:
|
||||||
|
case SWFTags.DefineBitsLossless2:
|
||||||
|
tag.characterId = buff.readUIntLE(16);
|
||||||
|
tag.bitmapFormat = buff.readUInt8();
|
||||||
|
tag.bitmapWidth = buff.readUIntLE(16);
|
||||||
|
tag.bitmapHeight = buff.readUIntLE(16);
|
||||||
|
var restLength = tagHeader.length - 7;
|
||||||
|
if (tag.bitmapFormat == 3) {
|
||||||
|
tag.bitmapColorTableSize = buff.readUInt8();
|
||||||
|
restLength--;
|
||||||
|
}
|
||||||
|
tag.zlibBitmapData = buff.buffer.slice(buff.pointer, buff.pointer + restLength);
|
||||||
|
buff.pointer += restLength;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
tag.data = buff.buffer.slice(buff.pointer, buff.pointer + tagHeader.length);
|
||||||
|
buff.pointer += tagHeader.length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tags.push(tag);
|
||||||
|
}
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads tags and their contents, passaing a SWF object to callback
|
||||||
|
*
|
||||||
|
* @param {SWFBuffer} buff
|
||||||
|
* @param {Buffer} compressed_buff
|
||||||
|
* @param {function} callback
|
||||||
|
* @api private
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function readSWFBuff(buff, compressed_buff, next) {
|
||||||
|
buff.seek(3);// start
|
||||||
|
|
||||||
|
if (buff.length < 9) {
|
||||||
|
if (isSync) throw new Error("Buffer is to small, must be greater than 9 bytes.");
|
||||||
|
return next(new Error("Buffer is to small, must be greater than 9 bytes."));
|
||||||
|
}
|
||||||
|
var swf = {
|
||||||
|
version : buff.readUInt8(),
|
||||||
|
fileLength : {
|
||||||
|
compressed : compressed_buff.length,
|
||||||
|
uncompressed : buff.readUIntLE(32)
|
||||||
|
},
|
||||||
|
frameSize : buff.readRect(), // Returns a RECT object. i.e : { x : 0, y : 0, width : 200, height: 300 }
|
||||||
|
frameRate : buff.readUIntLE(16)/256,
|
||||||
|
frameCount : buff.readUIntLE(16)
|
||||||
|
}
|
||||||
|
, isSync = 'function' !== typeof next;
|
||||||
|
|
||||||
|
try {
|
||||||
|
swf.tags = readSWFTags(buff, swf);
|
||||||
|
} catch(e) {
|
||||||
|
if (isSync) throw e;
|
||||||
|
return next(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSync && swf || next( null, swf );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concat SWF Header with uncompressed Buffer
|
||||||
|
*
|
||||||
|
* @param {Buffer|ArrayBuffer} buff
|
||||||
|
* @param {Buffer|ArrayBuffer} swf
|
||||||
|
*/
|
||||||
|
function concatSWFHeader(buff, swf) {
|
||||||
|
return Buffer.concat([swf.slice(0, 8), buff]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uncompress SWF and start reading it
|
||||||
|
*
|
||||||
|
* @param {Buffer|ArrayBuffer} swf
|
||||||
|
* @param {function} callback
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function uncompress(swf, next) {
|
||||||
|
var compressed_buff = swf.slice(8)
|
||||||
|
, uncompressed_buff
|
||||||
|
, isSync = 'function' !== typeof next
|
||||||
|
, e;
|
||||||
|
|
||||||
|
// uncompress buffer
|
||||||
|
switch( swf[0] ) {
|
||||||
|
case 0x43 : // zlib compressed
|
||||||
|
if (isSync) {
|
||||||
|
uncompressed_buff = concatSWFHeader(zlib.unzipSync(compressed_buff), swf);
|
||||||
|
return readSWFBuff(new SWFBuffer(uncompressed_buff), swf);
|
||||||
|
}
|
||||||
|
|
||||||
|
const newBuffer = swf.slice(4);
|
||||||
|
const uncompressedLength = newBuffer.readUInt32LE();
|
||||||
|
const chunks = [];
|
||||||
|
|
||||||
|
let readLength = 0;
|
||||||
|
var decompressStream = zlib.createInflate()
|
||||||
|
.on('data', function (chunk) {
|
||||||
|
readLength += chunk.length;
|
||||||
|
chunks.push(chunk);
|
||||||
|
|
||||||
|
if (uncompressedLength - 8 === readLength) {
|
||||||
|
decompressStream.close();
|
||||||
|
}
|
||||||
|
//decompressStream.pause();
|
||||||
|
}).on('error', function(err) {
|
||||||
|
console.log(err);
|
||||||
|
//next(err);
|
||||||
|
}).on('close', function() {
|
||||||
|
readSWFBuff(new SWFBuffer( Buffer.concat(chunks) ), swf, next);
|
||||||
|
});
|
||||||
|
decompressStream.write(compressed_buff);
|
||||||
|
break;
|
||||||
|
case 0x46 : // uncompressed
|
||||||
|
return readSWFBuff(new SWFBuffer( swf ), swf, next);
|
||||||
|
break;
|
||||||
|
case 0x5a : // LZMA compressed
|
||||||
|
var lzmaProperties = compressed_buff.slice(4, 9);
|
||||||
|
compressed_buff = compressed_buff.slice(9);
|
||||||
|
|
||||||
|
var input_stream = new Stream();
|
||||||
|
input_stream.pos = 0;
|
||||||
|
input_stream.readByte = function() {
|
||||||
|
return this.pos >= compressed_buff.length ? -1 : compressed_buff[this.pos++];
|
||||||
|
};
|
||||||
|
|
||||||
|
var output_stream = new Stream();
|
||||||
|
output_stream.buffer = new Buffer(16384);
|
||||||
|
output_stream.pos = 0;
|
||||||
|
output_stream.writeByte = function(_byte) {
|
||||||
|
if (this.pos >= this.buffer.length) {
|
||||||
|
var newBuffer = new Buffer(this.buffer.length * 2);
|
||||||
|
this.buffer.copy(newBuffer);
|
||||||
|
this.buffer = newBuffer;
|
||||||
|
}
|
||||||
|
this.buffer[this.pos++] = _byte;
|
||||||
|
};
|
||||||
|
output_stream.getBuffer = function() {
|
||||||
|
// trim buffer
|
||||||
|
if (this.pos !== this.buffer.length) {
|
||||||
|
var newBuffer = new Buffer(this.pos);
|
||||||
|
this.buffer.copy(newBuffer, 0, 0, this.pos);
|
||||||
|
this.buffer = newBuffer;
|
||||||
|
}
|
||||||
|
return this.buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
lzma.decompress(lzmaProperties, input_stream, output_stream, -1);
|
||||||
|
uncompressed_buff = Buffer.concat([swf.slice(0, 8), output_stream.getBuffer()]);
|
||||||
|
|
||||||
|
return readSWFBuff(new SWFBuffer(uncompressed_buff), swf, next);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
e = new Error('Unknown SWF compressions');
|
||||||
|
|
||||||
|
if (isSync) {
|
||||||
|
throw e;
|
||||||
|
} else {
|
||||||
|
next(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if file is Buffer or ArrayBuffer
|
||||||
|
*
|
||||||
|
* @param {Buffer|ArrayBuffer) b
|
||||||
|
* @api private
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function isBuffer(b) {
|
||||||
|
return typeof Buffer !== "undefined" && Buffer.isBuffer(b) || b instanceof ArrayBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exposes Tags constants */
|
||||||
|
SWFReader.TAGS = SWFTags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads SWF file
|
||||||
|
*
|
||||||
|
* @param {String|Buffer}} file
|
||||||
|
* @param {function} next - if not a function, uses synchronous algorithm
|
||||||
|
* @api public
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
SWFReader.read = SWFReader.readSync = function(file, next) {
|
||||||
|
if (isBuffer(file)) {
|
||||||
|
/* File is already a buffer */
|
||||||
|
return uncompress(file, next);
|
||||||
|
} else {
|
||||||
|
/* Get the buffer */
|
||||||
|
if ('function' === typeof next) {
|
||||||
|
fs.readFile(file, function(err, swf) {
|
||||||
|
if ( err ) {
|
||||||
|
next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uncompress(swf, next);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return uncompress(fs.readFileSync(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
287
src/swf-reader/lib/swf-buffer.js
Normal file
287
src/swf-reader/lib/swf-buffer.js
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
|
||||||
|
var RECORDHEADER_LENTH_FULL = 0x3f
|
||||||
|
// null-character
|
||||||
|
, EOS = 0x00
|
||||||
|
, styleCountExt = 0xFF;
|
||||||
|
|
||||||
|
function readStyleArray(buffer, next) {
|
||||||
|
var styleArrayCount = buffer.readUInt8()
|
||||||
|
, styles = [];
|
||||||
|
|
||||||
|
if (styleArrayCount === styleCountExt)
|
||||||
|
styleArrayCount = buffer.readUIntLE(16);
|
||||||
|
|
||||||
|
for (var i = 0; i < styleArrayCount; i++)
|
||||||
|
styles.push(next(buffer));
|
||||||
|
|
||||||
|
return styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readFillStyle(buffer) {
|
||||||
|
var type = buffer.readUInt8()
|
||||||
|
, fillStyle = {
|
||||||
|
/**
|
||||||
|
* 0x00 = solid
|
||||||
|
* 0x10 = linear gradient fill
|
||||||
|
* 0x12 = radial gradient fill
|
||||||
|
* 0x13 = focal radial gradient fill (SWF 8 or later)
|
||||||
|
* 0x40 = repeating bitmap fill
|
||||||
|
* 0x41 = clipped bitmap fill
|
||||||
|
* 0x42 = non-smoothed repeating bitmap
|
||||||
|
* 0x43 = non-smoothed clipped bitmap
|
||||||
|
*/
|
||||||
|
fillStyleType : type
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0x00:
|
||||||
|
fillStyle.color = buffer.readRGBA();
|
||||||
|
break;
|
||||||
|
case 0x10, 0x12, 0x13:
|
||||||
|
console.log('Gradient');
|
||||||
|
break;
|
||||||
|
case 0x40, 0x41, 0x42, 0x43:
|
||||||
|
fillStyle.bitmapId = buffer.readUIntLE(16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fillStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readLineStyle(buffer) {
|
||||||
|
return {
|
||||||
|
width: buffer.readUIntLE(16)/20,
|
||||||
|
color: buffer.readRGBA()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function readShapeRecords(buffer) {
|
||||||
|
var shapeRecords = []
|
||||||
|
, typeFlag = buffer.readBits(1)
|
||||||
|
, shapeRecord
|
||||||
|
, eos;
|
||||||
|
|
||||||
|
while ((eos = buffer.readBits(5))) {
|
||||||
|
if (0 === typeFlag) {
|
||||||
|
shaperecord = {
|
||||||
|
type: 'STYLECHANGERECORD'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shapeRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Constructor of SWFBuffer object
|
||||||
|
*
|
||||||
|
* @param {Buffer} buffer
|
||||||
|
* @return Instance of SWFBuffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
function SWFBuffer( buffer ) {
|
||||||
|
if ( !Buffer.isBuffer( buffer ) ) {
|
||||||
|
throw new Error('Invalid buffer');
|
||||||
|
}
|
||||||
|
this.buffer = buffer;
|
||||||
|
this.pointer = 0;
|
||||||
|
this.position = 1;
|
||||||
|
this.current = 0;
|
||||||
|
this.length = buffer.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads unsigned 16 or 32 Little Endian Bits
|
||||||
|
* and advance pointer to next bits / 8 bytes
|
||||||
|
*
|
||||||
|
* @param {Number} bits
|
||||||
|
* @return {Number} Value read from buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readUIntLE = function( bits ) {
|
||||||
|
var value = 0;
|
||||||
|
try {
|
||||||
|
value = this.buffer['readUInt' + bits + 'LE'](this.pointer);
|
||||||
|
this.pointer += bits / 8;
|
||||||
|
} catch ( e ) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads unsigned 8 bit from the buffer
|
||||||
|
*
|
||||||
|
* @return {Number} Value read from buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readUInt8 = function() {
|
||||||
|
return this.buffer.readUInt8( this.pointer++ );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads 32-bit unsigned integers value encoded (1-5 bytes)
|
||||||
|
*
|
||||||
|
* @return {Number} 32-bit unsigned integer
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readEncodedU32 = function() {
|
||||||
|
var i = 5
|
||||||
|
, result = 0
|
||||||
|
, nb;
|
||||||
|
|
||||||
|
do
|
||||||
|
result += (nb = this.nextByte());
|
||||||
|
while((nb & 128) && --i);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an encoded data from buffer and returns a
|
||||||
|
* string using the specified character set.
|
||||||
|
*
|
||||||
|
* @param {String} encoding - defaults to 'utf8'
|
||||||
|
* @returns {String} Decoded string
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readString = function(encoding) {
|
||||||
|
var init = this.pointer;
|
||||||
|
while(this.readUInt8() !== EOS);
|
||||||
|
return this.buffer.toString(encoding || 'utf8', init, this.pointer - 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads RGB value
|
||||||
|
*
|
||||||
|
* @return {Array} Array of RGB value
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readRGB = function() {
|
||||||
|
return [this.readUInt8(), this.readUInt8(), this.readUInt8()];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads RGBA value
|
||||||
|
*
|
||||||
|
* @return {Array} Array of RGBA value
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readRGBA = function() {
|
||||||
|
var rgba = this.readRGB();
|
||||||
|
rgba.push(this.readUInt8());
|
||||||
|
return rgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads ShapeWithStyle structure
|
||||||
|
* used by the DefineShape tag.
|
||||||
|
*
|
||||||
|
* @return ShapeWithStyle structure
|
||||||
|
*/
|
||||||
|
SWFBuffer.prototype.readShapeWithStyle = function() {
|
||||||
|
return {
|
||||||
|
fillStyles : readStyleArray(this, readFillStyle),
|
||||||
|
lineStyles : readStyleArray(this, readLineStyle),
|
||||||
|
numFillBits : this.readBits(4),
|
||||||
|
numLineBits : this.readBits(4),
|
||||||
|
shapeRecords: readShapeRecords(this)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads RECORDHEADER from next tag in the buffer
|
||||||
|
*
|
||||||
|
* @return {Object} Tag code and length
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readTagCodeAndLength = function() {
|
||||||
|
var n = this.readUIntLE(16)
|
||||||
|
, tagType = n >> 6
|
||||||
|
, tagLength = n & RECORDHEADER_LENTH_FULL;
|
||||||
|
|
||||||
|
if ( n === 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( tagLength === RECORDHEADER_LENTH_FULL )
|
||||||
|
tagLength = this.readUIntLE(32);
|
||||||
|
|
||||||
|
return { code : tagType, length : tagLength };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads RECT format
|
||||||
|
*
|
||||||
|
* @return {Object} x, y, width and height of the RECT
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readRect = function() {
|
||||||
|
|
||||||
|
this.start();
|
||||||
|
|
||||||
|
var NBits = this.readBits(5)
|
||||||
|
, Xmin = this.readBits(NBits, true)/20
|
||||||
|
, Xmax = this.readBits(NBits, true)/20
|
||||||
|
, Ymin = this.readBits(NBits, true)/20
|
||||||
|
, Ymax = this.readBits(NBits, true)/20;
|
||||||
|
|
||||||
|
return {
|
||||||
|
x : Xmin,
|
||||||
|
y : Ymin,
|
||||||
|
width : (Xmax > Xmin ? Xmax - Xmin : Xmin - Xmax),
|
||||||
|
height : (Ymax > Ymin ? Ymax - Ymin : Ymin - Ymax)
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets internal pointer to the specified position;
|
||||||
|
*
|
||||||
|
* @param {Number} pos
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.seek = function( pos ) {
|
||||||
|
this.pointer = pos % this.buffer.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets position and sets current to next Byte in buffer
|
||||||
|
*/
|
||||||
|
SWFBuffer.prototype.start = function() {
|
||||||
|
this.current = this.nextByte();
|
||||||
|
this.position = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets next Byte in the buffer and Increment internal pointer
|
||||||
|
*
|
||||||
|
* @return {Number} Next byte in buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.nextByte = function() {
|
||||||
|
return this.pointer > this.buffer.length ? null : this.buffer[ this.pointer++ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads b bits from current byte in buffer
|
||||||
|
*
|
||||||
|
* @param {Number} b
|
||||||
|
* @return {Number} Bits read from buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
SWFBuffer.prototype.readBits = function( b, signed ) {
|
||||||
|
var n = 0
|
||||||
|
, r = 0
|
||||||
|
, sign = signed && ++n && ((this.current >> (8-this.position++)) & 1) ? -1 : 1;
|
||||||
|
|
||||||
|
while( n++ < b ) {
|
||||||
|
if ( this.position > 8 ) this.start();
|
||||||
|
|
||||||
|
r = (r << 1 ) + ((this.current >> (8-this.position++)) & 1);
|
||||||
|
}
|
||||||
|
return sign * r;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Exposes class */
|
||||||
|
exports = module.exports = SWFBuffer;
|
82
src/swf-reader/lib/swf-tags.js
Normal file
82
src/swf-reader/lib/swf-tags.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* Defines constants on exports object
|
||||||
|
*
|
||||||
|
* @param {String} name
|
||||||
|
* @param {Mixed} value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function define(name, value) {
|
||||||
|
Object.defineProperty(exports, name, {
|
||||||
|
value : value,
|
||||||
|
enumerable : true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SWF Tags Type */
|
||||||
|
|
||||||
|
define('End', 0);
|
||||||
|
define('ShowFrame', 1);
|
||||||
|
define('DefineShape', 2);
|
||||||
|
define('PlaceObject', 4);
|
||||||
|
define('RemoveObject', 5);
|
||||||
|
define('DefineBits', 6);
|
||||||
|
define('DefineButton', 7);
|
||||||
|
define('JPEGTables', 8);
|
||||||
|
define('SetBackgroundColor', 9);
|
||||||
|
define('DefineFont', 10);
|
||||||
|
define('DefineText', 11);
|
||||||
|
define('DoAction', 12);
|
||||||
|
define('DefineFontInfo', 13);
|
||||||
|
define('DefineSound', 14);
|
||||||
|
define('StartSound', 15);
|
||||||
|
define('DefineButtonSound', 17);
|
||||||
|
define('SoundStreamHead', 18);
|
||||||
|
define('SoundStreamBlock', 19);
|
||||||
|
define('DefineBitsLossless', 20);
|
||||||
|
define('DefineBitsJPEG2', 21);
|
||||||
|
define('DefineShape2', 22);
|
||||||
|
define('DefineButtonCxform', 23);
|
||||||
|
define('Protect', 24);
|
||||||
|
define('PlaceObject2', 26);
|
||||||
|
define('RemoveObject2', 28);
|
||||||
|
define('DefineShape3', 32);
|
||||||
|
define('DefineText2', 33);
|
||||||
|
define('DefineButton2', 34);
|
||||||
|
define('DefineBitsJPEG3', 35);
|
||||||
|
define('DefineBitsLossless2', 36);
|
||||||
|
define('DefineEditText', 37);
|
||||||
|
define('DefineSprite', 39);
|
||||||
|
define('SerialNumber', 41);
|
||||||
|
define('FrameLabel', 43);
|
||||||
|
define('SoundStreamHead2', 45);
|
||||||
|
define('DefineMorphShape', 46);
|
||||||
|
define('DefineFont2', 48);
|
||||||
|
define('ExportAssets', 56);
|
||||||
|
define('ImportAssets', 57);
|
||||||
|
define('EnableDebugger', 58);
|
||||||
|
define('DoInitAction', 59);
|
||||||
|
define('DefineVideoStream', 60);
|
||||||
|
define('VideoFrame', 61);
|
||||||
|
define('DefineFontInfo2', 62);
|
||||||
|
define('EnableDebugger2', 64);
|
||||||
|
define('ScriptLimits', 65);
|
||||||
|
define('SetTabIndex', 66);
|
||||||
|
define('FileAttributes', 69);
|
||||||
|
define('PlaceObject3', 70);
|
||||||
|
define('ImportAssets2', 71);
|
||||||
|
define('DefineFontAlignZones', 73);
|
||||||
|
define('CSMTextSettings', 74);
|
||||||
|
define('DefineFont3', 75);
|
||||||
|
define('SymbolClass', 76);
|
||||||
|
define('Metadata', 77);
|
||||||
|
define('DefineScalingGrid', 78);
|
||||||
|
define('DoABC', 82);
|
||||||
|
define('DefineShape4', 83);
|
||||||
|
define('DefineMorphShape2', 84);
|
||||||
|
define('DefineSceneAndFrameLabelData', 86);
|
||||||
|
define('DefineBinaryData', 87);
|
||||||
|
define('DefineFontName', 88);
|
||||||
|
define('StartSound2', 89);
|
||||||
|
define('DefineBitsJPEG4', 90);
|
||||||
|
define('DefineFont4', 91);
|
||||||
|
//define('TagMax' (DefineFont4 + 1)
|
@ -5,7 +5,6 @@ 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>;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {writeFileSync} from "fs";
|
import {writeFileSync} from "fs";
|
||||||
|
|
||||||
const SWFReader = require('@gizeta/swf-reader');
|
const SWFReader = require('../swf-reader/index.js');
|
||||||
|
|
||||||
const _encoder = require('png-stream/encoder');
|
const _encoder = require('png-stream/encoder');
|
||||||
|
|
||||||
|
@ -11,13 +11,13 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"allowJs": false,
|
"allowJs": true,
|
||||||
"baseUrl": "./src",
|
"baseUrl": "./src",
|
||||||
"outDir": "./dist"
|
"outDir": "./dist"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/configuration.json",
|
"src/configuration.json",
|
||||||
"src/**/*.ts"
|
"src/**/*"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
|
Loading…
Reference in New Issue
Block a user