After discovering how to compress / decompress swf files via the Java Deflater / Inflater api, I’ve abandoned the RandomAccessFile method of reading the swf and moved to just using a FileInputStream to create a byte array which can then be examined byte by byte, or, in some cases, bit by bit. The end result is a lightweight Java solution for parsing the header of any swf irregardless of whether the swf is compressed or uncompressed.
Another significant change has been reading the swf size from the header rather than just looking at the number of bytes in the file. This is critical when reading a compressed swf since the header contains information about the number of bytes the file will consume when uncompressed.
As with the previous version you are able extract the following information from the header:
- file signature ( “FWS” if uncompressed or “CWS” if compressed)
- version
- size (in bytes)
- width (getWidth converts the twips to pixels for you automatically)
- height( again twips to pixel conversion is taken care of)
- frame rate
- frame count
I’m again providing both a jar an java source files:
I’m really interested in tackling reading / writing metadata in the swf format, so if anyone has ideas or suggestions give me a yell.
***UPDATE***
I found a bug which effects reading the frame rate and frame count. Because the swf width and height are stored in a “packed” format (the number of bytes needed to store the dimensions varies) I couldn’t use an arbitrary count to read frame rate and frame count. Instead the parseHeader method now stores an iterator that keeps track of the next byte that needs to be read. The jar and source files available above have been updated accordingly.
***UPDATE 2***
Several users noted a bug where large dimension swf files (width & height) were failing to be read. Anson, noted that the using the >>> operator to deal with right shifts does not work as defined in the Java documentation. Instead, every time a right shift is needed we to mask and do a standard right shift - (someByte[0] & 0xff) >> 3. The jar and source files have been updated in the links above.
11 Comments
As the implementation of unsigned right shift in Java is not as expected, your parseHeader() does not work for all flash files. To fix the problem, simply change the following line
nbits = ( rect[0] >>> 3 );
to
nbits = (rect[0] & 0xff) >> 3;
For more details:
http://www.cs.utsa.edu/~wagner/laws/Abytes.html
Hello andrus,
I was very happy when you made a JAR version of this tool but I found a bug and I’m not so good with bitwise operators then it’s difficult for me to fix it.
The bug appears when you’re trying to get info from an SWF bigger than 810 in width or height.
Do you know why ?
Thx in advance.
OrtOfOn
Sorry…. little mistake in my first comment…
The bug appears when you’re trying to get info from an SWF bigger than 819 in width or height.
819 is the limit size of the stage to make the swfheader working.
Thx.
Yep, I’m aware of that bug and have fixed. I updated the source files on the Web page, but I must not of updated the jar. The issue was the result of using an arbitrary byte position when reading in the packed bit “rectangle” construct the swf format uses.
I’ll compile a new jar, test and post an update.
Brooks
Very Cool, thx Brooks !!!
OrtOfOn
doesnt work with that one
[link removed]
(I know, this is disgusting but i’m serious)
Ooops, the problem is
swf.getFrameCount() is
It seems to be ok by remplacing
frameCount = ( frameCount 127 for the second swf[bytePointer] lead to the problem.
Yep, I noticed that bug regarding frame count awhile ago and fixed, but I apparently forgot to upload the files. I’ve now checked to make sure that the header reader accurately reads the number of frames up to the swf file format imposed limit of 16000. The files on the website have been updated accordingly.
Hello Andrus!
I tested your useful code with 2 swf files of v.5 and v.7.
It works correct for v.5
But for v.7 of SWF, getWidth and getHeight return wrong values
Those values are double converted from twips.
In the same time maxX and maxY contain correct size in pixels(!)
The SWFHeader.java is not matching the classes in swfheader.jar. In SWFHeader.java it extends SWFCompression, but in the jar there is no SWFCompression, and SWFHeader doesn’t extends SWFCompression. Is the jar the latest one? It would be nice if you could post the current code.
The jar version is also printing some debug info to the output.
Also in both version an IOException it prints to standard error instead of throwing an exception, and at least the source code does the same when it finds an invalid file, and having the code I can just add this improvements.