{"id":1204,"date":"2011-01-17T13:34:47","date_gmt":"2011-01-17T18:34:47","guid":{"rendered":"http:\/\/www.lonhosford.com\/lonblog\/?p=1204"},"modified":"2015-07-31T18:25:51","modified_gmt":"2015-07-31T23:25:51","slug":"read-flash-swf-header-in-air-with-parsley-framework","status":"publish","type":"post","link":"https:\/\/www.lonhosford.com\/lonblog\/2011\/01\/17\/read-flash-swf-header-in-air-with-parsley-framework\/","title":{"rendered":"Read Flash SWF Header in AIR with Parsley Framework"},"content":{"rendered":"<p>I was asked to look for open source tools to read the basic information contained in a Flash swf file. Most of the items you find are for reverse engineering swf files. In the search process I found two sources to parse the swf file header. <img loading=\"lazy\" decoding=\"async\" alt=\"\" src=\"http:\/\/lh6.ggpht.com\/_e5pwU0LJbN8\/TTSEk55KhzI\/AAAAAAAAFxY\/LhkeY0x2TOA\/s800\/adobe-swf_header_published.png\" class=\"alignleft\" width=\"400\" height=\"235\" \/><\/p>\n<p>The first was a <a href=\"http:\/\/www.fecj.org\/extra\/SWF-info-and-Frame-Rate-extraction.html\"  target = \"_blank\">php script<\/a> written by Carlos Falo Herv\u00e1. You need to scroll down to the end of the post to find his work. This works just fine if you want to run off a server. <\/p>\n<p>The second is <a href=\"http:\/\/simplistika.com\/parsing-reading-swf-header\/\"  target = \"_blank\">written in Actionscript<\/a> for Flash CS5. Only the author&#8217;s handle, jared, and not the author&#8217;s name is not available at the site. The download works nice and you can run from the author&#8217;s web page. You need type or paste in a url for the swf file name. The code is all dropped in on the first frame.<\/p>\n<p>This site also provided a nice link to the <a href=\"http:\/\/www.adobe.com\/content\/dam\/Adobe\/en\/devnet\/swf\/pdf\/swf_file_format_spec_v10.pdf\"  target = \"_blank\">Adobe SWF file version 10 specifications<\/a> if you care to know. Page 25 has the key information on the SWF header. This is also repeated in the SWFHeaderParser parser class presented in this post.<\/p>\n<p>I took the code for the second example and created a drag and drop version Adobe Air. First I separated the code into two Actionscript classes. One for parsing and one for loading swf file bytes. These classes are named respectively SWFHeaderParser and SWFHeaderLoader. I added a value object, SWFHeader_vo, to pass around the values. <\/p>\n<p>I glued those items together in an Air project using the Parsley framework. This gave me a chance to use Parsley DynamicObject for the SWFHeaderLoader class that loads the SWF file for the parser.<\/p>\n<p>The result is a fully decoupled version that serves as a super example of model-view-controller using Parsley for an Air app.<\/p>\n<p>Download files:<br \/>\nHere is the Flex project if you want to explore the code and the Air installer in case you just want the tool.<\/p>\n<ul style = \"padding-top:10px\">\n<li><a href=\"https:\/\/www.lonhosford.com\/content\/flex\/swf\/SWFHeader_Air.fxp\"  onClick=\"javascript: pageTracker._trackPageview('\/downloads\/SWFHeader_Air.fxp'); \">Flex Builder 4 Flex Project<\/a><\/li>\n<li><a href=\"https:\/\/www.lonhosford.com\/content\/flex\/swf\/SWFHeader.air\"  onClick=\"javascript: pageTracker._trackPageview('\/downloads\/SWFHeader.air'); \">Adobe Air Installer<\/a><\/li>\n<\/ul>\n<p>[ad name=&#8221;Google Adsense&#8221;]<\/p>\n<p><strong>SWF Parser &#8211; SWFHeaderParser.as<\/strong><br \/>\nThe parser class is first as that is what you might want to integrate into your code. Note it returns the SWFHeader_vo class. The comments are scant in this class since I did write the code and only converted it into a class, returned a value object and removed code not specific to parsing the bytes. The value object is created and populated on lines 85 &#8211; 95.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage swf\r\n{\r\n\timport flash.geom.Rectangle;\r\n\timport flash.utils.ByteArray;\r\n\timport flash.utils.Endian;\r\n\timport vo.SWFHeader_vo;\r\n\t\/**\r\n\t * SWF Header parsing. Code adapted from http:\/\/simplistika.com\/parsing-reading-swf-header\/.\r\n\t * *\/\r\n\tpublic class SWFHeaderParser\r\n\t{\r\n\t\tprivate var xByte : uint;\r\n\t\tprivate var xNBits : int;\r\n\t\tprivate var xOffset : int;\r\n\t\tpublic function SWFHeaderParser()\r\n\t\t{\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Get a SWFHeader_vo object from a ByteArray\r\n\t\t * @param swfByteArray Any byte array, but expecting a SWF binary file or header from SWF file.\r\n\t\t * @return Parsed values in SWFHeader_vo object.\r\n\t\t * *\/\r\n\t\tpublic function parseBytes(swfByteArray : ByteArray) : SWFHeader_vo\r\n\t\t{\r\n\t\t\treturn fParse(swfByteArray);\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Original code from http:\/\/simplistika.com\/parsing-reading-swf-header\/ changed to \r\n\t\t * return SWFHeader_vo object.\r\n\t\t * *\/\r\n\t\tprivate function fParse(v : ByteArray) : SWFHeader_vo\r\n\t\t{\r\n\t\t\t\/*\r\n\t\t\tField\t\tType \tComment\r\n\t\t\t\t\t\t\t\tSignature byte\r\n\t\t\tSignature\tUI8\t\t&quot;F&quot; indicates uncompressed\r\n\t\t\t\t\t\t\t\t&quot;C&quot; indicates compressed (SWF 6 and later only)\r\n\t\t\tSignature\tUI8\t\tSignature byte always &quot;W&quot;\r\n\t\t\tSignature\tUI8\t\tSignature byte always &quot;S&quot;\r\n\t\t\t\r\n\t\t\tVersion\t\tUI8\t\tSingle byte file version\r\n\t\t\tFileLength\tUI32\tLength of entire file in bytes\r\n\t\t\tFrameSize\tRECT\tFrame size in twips\r\n\t\t\tFrameRate\tUI16\tFrame delay in 8.8 fixed number of frames per second\r\n\t\t\tFrameCount\tUI16\tTotal number of frames in file\r\n\t\t\tThe header begins with a three-byte signature of either 0\u00d746, 0\u00d757, 0\u00d753 (&quot;FWS&quot;); or 0\u00d743, 0\u00d757, 0\u00d753 (\u201cCWS\u201d). An FWS signature indicates an uncompressed SWF file; CWS indicates that the entire file after the first 8 bytes (that is, after the FileLength field) was compressed by using the ZLIB open standard. The data format that the ZLIB library uses is described by Request for Comments (RFCs) documents 1950 to 1952. CWS file compression is permitted in SWF 6 or later only.\r\n\t\t\t\r\n\t\t\tA one-byte version number follows the signature. \r\n\t\t\tThe version number is not an ASCII character, \r\n\t\t\tbut an 8-bit number. For example, for SWF 4, the version byte is 0\u00d704, not the \r\n\t\t\tASCII character \u201c4? (0\u00d734). The FileLength field is the total length of the \r\n\t\t\tSWF file, including the header. If this is an uncompressed SWF file (FWS signature), \r\n\t\t\tthe FileLength field should exactly match the file size. If this is a compressed SWF file \r\n\t\t\t(CWS signature), the FileLength field indicates the total length of the file after decompression, \r\n\t\t\tand thus generally does not match the file size. Having the uncompressed size available can make \r\n\t\t\tthe decompression process more efficient. The FrameSize field defines the width and height \r\n\t\t\tof the on-screen display. This field is stored as a RECT structure, meaning that its size \r\n\t\t\tmay vary according to the number of bits needed to encode the coordinates. The FrameSize \r\n\t\t\tRECT always has Xmin and Ymin value of 0; the Xmax and Ymax members define the width and \r\n\t\t\theight. The FrameRate is the desired playback rate in frames per second.\r\n\t\t\t\r\n\t\t\tSource: http:\/\/simplistika.com\/parsing-reading-swf-header\/\r\n\t\t\t\r\n\t\t\t*\/\r\n\t\t\tvar vFormat : String;\r\n\t\t\tvar vSwfVersion : int;\r\n\t\t\tvar vFileLength : int;\r\n\t\t\tvar vFrameRate : int;\r\n\t\t\tvar vTotalFrames : int;\r\n\t\t\tvar vFrameSize : Rectangle;\r\n\t\t\tv.endian = Endian.LITTLE_ENDIAN;\r\n\t\t\tvFormat = v.readUTFBytes(3);\r\n\t\t\tvSwfVersion = v.readByte();\r\n\t\t\tvFileLength = v.readUnsignedInt();\r\n\t\t\tv.readBytes(v);\r\n\t\t\tv.length -= 8;\r\n\t\t\tif (vFormat == &quot;CWS&quot;)\r\n\t\t\t\tv.uncompress();\r\n\t\t\tv.position = 0;\r\n\t\t\tvFrameSize = new Rectangle();\r\n\t\t\tvFrameSize.left = xfReadNBits(v, true) \/ 20;\r\n\t\t\tvFrameSize.right = xfReadNBits(v) \/ 20;\r\n\t\t\tvFrameSize.top = xfReadNBits(v) \/ 20;\r\n\t\t\tvFrameSize.bottom = xfReadNBits(v) \/ 20;\r\n\t\t\tvFrameRate = v.readUnsignedByte() \/ 256 + v.readUnsignedByte();\r\n\t\t\tvTotalFrames = v.readUnsignedShort();\r\n\t\t\tvar swfHeader_vo:SWFHeader_vo = new SWFHeader_vo();\r\n\t\t\tswfHeader_vo.format = vFormat;\r\n\t\t\tswfHeader_vo.swfVersion = vSwfVersion;\r\n\t\t\tswfHeader_vo.sizeUncompressed = vFileLength;\r\n\t\t\tswfHeader_vo.width = vFrameSize.width;\r\n\t\t\tswfHeader_vo.height =vFrameSize.height;\r\n\t\t\tswfHeader_vo.frameRate = vFrameRate;\r\n\t\t\tswfHeader_vo.totalFrames = vTotalFrames;\r\n\t\t\treturn swfHeader_vo;\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Original code from http:\/\/simplistika.com\/parsing-reading-swf-header\/.\r\n\t\t * *\/\r\n\t\tprivate function xfReadNBits(v : ByteArray, vStart : Boolean = false) : uint\r\n\t\t{\r\n\t\t\tvar n : uint;\r\n\t\t\tif (vStart)\r\n\t\t\t{\r\n\t\t\t\txByte = v.readUnsignedByte();\r\n\t\t\t\txNBits = xByte &gt;&gt; 3;\r\n\t\t\t\txOffset = 3;\r\n\t\t\t}\r\n\t\t\tn = xByte &lt;&lt; (32 - xOffset) &gt;&gt; (32 - xNBits);\r\n\t\t\txOffset -= xNBits;\r\n\t\t\twhile (xOffset &lt; 0)\r\n\t\t\t{\r\n\t\t\t\txByte = v.readUnsignedByte();\r\n\t\t\t\tn |= (xOffset &lt; -8) ? (xByte &lt;&lt; (-xOffset - 8)) : (xByte &gt;&gt; (-xOffset - 8));\r\n\t\t\t\txOffset += 8;\r\n\t\t\t}\r\n\t\t\treturn n;\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>SWF Loader &#8211; SWFHeaderLoader.as<\/strong><br \/>\nThis is my class to load the SWF and it uses Parsley messaging. If you do not intend to use Parsley, you need to add your own messaging. <\/p>\n<p>Most of this is standard URLLoader coding. <\/p>\n<p>The SWFHeaderParser is called on line 62. On line 63, the actual bytes are not gotten from the SWFHeaderParser. So it can be a bit misleading that that is information found in the SWF header. The SWF header only contains the uncompressed file size.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage swf\r\n{\r\n\timport events.SWFHeaderLoaderCompleteEvent;\r\n\timport events.SWFHeaderLoaderErrorEvent;\r\n\timport events.SWFHeaderLoaderProgressEvent;\r\n\timport flash.events.Event;\r\n\timport flash.events.HTTPStatusEvent;\r\n\timport flash.events.IOErrorEvent;\r\n\timport flash.events.ProgressEvent;\r\n\timport flash.events.SecurityErrorEvent;\r\n\timport flash.net.URLLoader;\r\n\timport flash.net.URLLoaderDataFormat;\r\n\timport flash.net.URLRequest;\r\n\timport models.SWFHeaderModel;\r\n\timport vo.SWFHeader_vo;\r\n\t\/**\r\n\t * Byte loader for a SWF file.\r\n\t * *\/\r\n\tpublic class SWFHeaderLoader \r\n\t{\r\n\t\t\/**\r\n\t\t * Has a URLLoader\r\n\t\t * *\/\r\n\t\tprivate var urlLoader:URLLoader;\r\n\t\t\/**\r\n\t\t * Model\r\n\t\t * *\/\r\n\t\t&#x5B;Inject]\r\n\t\tpublic var model:SWFHeaderModel;\r\n\t\t\/**\r\n\t\t * Receives Parsley messages.\r\n\t\t * *\/\r\n\t\t&#x5B;MessageDispatcher]\r\n\t\tpublic var dispatcher:Function;\r\n\t\t\/**\r\n\t\t * Load the bytes from a file.\r\n\t\t * *\/\r\n\t\tpublic function load(url:String):void\r\n\t\t{\r\n\t\t\turlLoader = new URLLoader();\r\n\t\t\turlLoader.addEventListener(Event.COMPLETE, urlLoader_completeEventHandler);\r\n\t\t\turlLoader.addEventListener(ProgressEvent.PROGRESS, urlLoader_progressHandler);\r\n\t\t\turlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, urlLoader_securityErrorHandler);\r\n\t\t\turlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, urlLoader_httpStatusHandler);\r\n\t\t\turlLoader.addEventListener(IOErrorEvent.IO_ERROR, urlLoader_ioErrorHandler);\r\n\t\t\turlLoader.dataFormat = URLLoaderDataFormat.BINARY;\r\n\t\t\turlLoader.load( new URLRequest(url) );\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Handler for the urlLoader ProgressEvent.PROGRESS event.\r\n\t\t * *\/\r\n\t\tprivate function urlLoader_progressHandler(event:ProgressEvent):void \r\n\t\t{\r\n\t\t\tdispatcher(new SWFHeaderLoaderProgressEvent(SWFHeaderLoaderProgressEvent.PROGRESS, event.bytesLoaded, event.bytesTotal));\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Handler for the urlLoader Event.COMPLETE event.\r\n\t\t * *\/\r\n\t\tprivate function urlLoader_completeEventHandler(event:Event):void\r\n\t\t{\r\n\t\t\tvar swfHeader_vo:SWFHeader_vo = new SWFHeader_vo();\r\n\t\t\tswfHeader_vo  = new SWFHeaderParser().parseBytes(urlLoader.data);\r\n\t\t\tswfHeader_vo.sizeCompressed = urlLoader.bytesLoaded;\r\n\t\t\tdispatcher(new SWFHeaderLoaderCompleteEvent(SWFHeaderLoaderCompleteEvent.COMPLETE, swfHeader_vo));\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Handler for the urlLoader SecurityErrorEvent.SECURITY_ERROR event.\r\n\t\t * *\/\r\n\t\tprivate function urlLoader_securityErrorHandler(event:SecurityErrorEvent):void \r\n\t\t{\r\n\t\t\tdispatcher(new SWFHeaderLoaderErrorEvent(SWFHeaderLoaderErrorEvent.SECURITY_ERROR));\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Handler for the urlLoader HTTPStatusEvent.HTTP_STATUS event.\r\n\t\t * *\/\r\n\t\tprivate function urlLoader_httpStatusHandler(event:HTTPStatusEvent):void \r\n\t\t{\r\n\t\t\tif (event.status != 200 &amp;&amp; event.status != 0)\r\n\t\t\t{\r\n\t\t\t\tdispatcher(new SWFHeaderLoaderErrorEvent(SWFHeaderLoaderErrorEvent.HTTP_ERROR));\r\n\t\t\t}\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Handler for the urlLoader IOErrorEvent.IO_ERROR event.\r\n\t\t * *\/\r\n\t\tprivate function urlLoader_ioErrorHandler(event:IOErrorEvent):void \r\n\t\t{\r\n\t\t\tdispatcher(new SWFHeaderLoaderErrorEvent(SWFHeaderLoaderErrorEvent.IO_ERROR));\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>SWF Header Value Object &#8211; SWFHeader_vo.as<\/strong><br \/>\nThe value object I use in the SWFHeaderLoader and SWFHeaderParser.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage vo\r\n{\r\n\t\/**\r\n\t * Defines the values in the SWF file header record needed for app\r\n\t * *\/\r\n\t&#x5B;Bindable]\r\n\tpublic class SWFHeader_vo\r\n\t{\r\n\t\tpublic var format:String;\t\t\t\/\/\t3 characters.\r\n\t\t\t\t\t\t\t\t\t\t\t\/\/  First character:\r\n\t\t\t\t\t\t\t\t\t\t\t\/\/  \t&quot;F&quot; indicates uncompressed.\r\n\t\t\t\t\t\t\t\t\t\t\t\/\/ \t\t&quot;C&quot; indicates compressed (SWF 6 and later only).\r\n\t\t\t\t\t\t\t\t\t\t\t\/\/  Second character always &quot;W&quot;.\r\n\t\t\t\t\t\t\t\t\t\t\t\/\/  Third character always &quot;S&quot;.\r\n\t\tpublic var swfVersion:Number;\t\t\/\/\tThe swf version.\r\n\t\tpublic var frameRate:Number;\t\t\/\/\tFrame rate.\r\n\t\tpublic var totalFrames:Number;\t\t\/\/\tNumber of frames on main timeline.\r\n\t\tpublic var width:Number;\t\t\t\/\/\tStage width.\r\n\t\tpublic var height:Number;\t\t\t\/\/\tStage height.\r\n\t\tpublic var sizeUncompressed:Number;\t\/\/\tFile size before compression.\r\n\t\tpublic var sizeCompressed:Number;\t\/\/\tActual file size.\r\n\t}\r\n}\r\n<\/pre>\n<p>[ad name=&#8221;Google Adsense&#8221;]<br \/>\nThe remainder code listings are the wiring into a Parsley Framework and published as an Adobe Air project.<\/p>\n<p><strong>Application Class &#8211; SWFHeader.mxml<\/strong><\/p>\n<p>This is the application mxml file. Gotta love how Parsley helps make these application  mxml files minimal.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;!--- \r\nApplication container\r\n--&gt;\r\n&lt;s:WindowedApplication xmlns:fx=&quot;http:\/\/ns.adobe.com\/mxml\/2009&quot; \r\n\t\t\t\t\t   xmlns:s=&quot;library:\/\/ns.adobe.com\/flex\/spark&quot; \r\n\t\t\t\t\t   xmlns:mx=&quot;library:\/\/ns.adobe.com\/flex\/mx&quot;\r\n\t\t\t\t\t   xmlns:parsley=&quot;http:\/\/www.spicefactory.org\/parsley&quot; \r\n\t\t\t\t\t   xmlns:views=&quot;views.*&quot;\r\n\t\t\t\t\t   height = &quot;450&quot;\r\n\t\t\t\t\t   backgroundAlpha=&quot;0&quot;\r\n\t\t\t\t\t   showStatusBar=&quot;false&quot; \t\t\t\t\t&gt;\r\n\t&lt;fx:Declarations&gt;\r\n\t\t&lt;!-- Place non-visual elements (e.g., services, value objects) here --&gt;\r\n\t\t&lt;parsley:ContextBuilder config=&quot;ParsleyConfiguration&quot;  \/&gt;\r\n\t\t&lt;parsley:Configure\/&gt;\r\n\t&lt;\/fx:Declarations&gt;\r\n\t&lt;views:Main  \/&gt;\r\n&lt;\/s:WindowedApplication&gt;\r\n<\/pre>\n<p><strong>Parsley Configuration File &#8211; ParsleyConfiguration.mxml<\/strong><br \/>\nMy first example that uses a Parsley DynamicObject. It is the SWFHeaderLoader class. I had a lot of silent failures before I could get this to stick. The result is that Parsley manages objects made from SWFHeaderLoader so we can have Parsley messaging and insertions. Only tried it with one object however.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;!--- \r\nParsley framework configuration file\r\n--&gt;\r\n&lt;Objects \r\n\txmlns:fx=&quot;http:\/\/ns.adobe.com\/mxml\/2009&quot;\r\n\txmlns=&quot;http:\/\/www.spicefactory.org\/parsley&quot;\r\n\txmlns:spicefactory=&quot;http:\/\/www.spicefactory.org\/parsley&quot;\r\n\txmlns:models=&quot;models.*&quot; \r\n\txmlns:controllers=&quot;controllers.*&quot; \r\n\txmlns:s=&quot;library:\/\/ns.adobe.com\/flex\/spark&quot; \r\n\t&gt;\r\n\t&lt;fx:Script&gt;\r\n\t\t&lt;!&#x5B;CDATA&#x5B;\r\n\t\t\t\/\/ Required for DynamicObject SWFHeaderLoader.\r\n\t\t\timport swf.*; \r\n\t\t]]&gt;\r\n\t&lt;\/fx:Script&gt;\r\n\t&lt;fx:Declarations&gt;\r\n\t\t&lt;!--\r\n\t\tParsley defined objects.\r\n\t\t--&gt;\r\n\t\t&lt;spicefactory:DynamicObject type = &quot;{SWFHeaderLoader}&quot; \/&gt;\r\n\t\t&lt;models:ApplicationModel\/&gt;\r\n\t\t&lt;models:SWFHeaderModel\/&gt;\r\n\t\t&lt;controllers:ApplicationController\/&gt;\r\n\t&lt;\/fx:Declarations&gt;\r\n&lt;\/Objects&gt;\r\n<\/pre>\n<p><strong>Air Application Descriptor File &#8211; SWFHeader-app.xml<\/strong><br \/>\nKey here is that this an Air 2.0 project indicated on line 2 and line 8.<\/p>\n<pre class=\"brush: xml; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; standalone=&quot;no&quot;?&gt;\r\n&lt;application xmlns=&quot;http:\/\/ns.adobe.com\/air\/application\/2.0&quot;&gt;\r\n\r\n&lt;!-- Adobe AIR Application Descriptor File Template.\r\n\r\n\tSpecifies parameters for identifying, installing, and launching AIR applications.\r\n\r\n\txmlns - The Adobe AIR namespace: http:\/\/ns.adobe.com\/air\/application\/2.0\r\n\t\t\tThe last segment of the namespace specifies the version \r\n\t\t\tof the AIR runtime required for this application to run.\r\n\t\t\t\r\n\tminimumPatchLevel - The minimum patch level of the AIR runtime required to run \r\n\t\t\tthe application. Optional.\r\n--&gt;\r\n\r\n\t&lt;!-- The application identifier string, unique to this application. Required. --&gt;\r\n\t&lt;id&gt;SwfHeader&lt;\/id&gt;\r\n\r\n\t&lt;!-- Used as the filename for the application. Required. --&gt;\r\n\t&lt;filename&gt;SWFHeaderInspector&lt;\/filename&gt;\r\n\r\n\t&lt;!-- The name that is displayed in the AIR application installer. \r\n\t     May have multiple values for each language. See samples or xsd schema file. Optional. --&gt;\r\n\t&lt;name&gt;SWF Header Inspector&lt;\/name&gt;\r\n\r\n\t&lt;!-- An application version designator (such as &quot;v1&quot;, &quot;2.5&quot;, or &quot;Alpha 1&quot;). Required. --&gt;\r\n\t&lt;version&gt;v0.01&lt;\/version&gt;\r\n\r\n\t&lt;!-- Description, displayed in the AIR application installer.\r\n\t     May have multiple values for each language. See samples or xsd schema file. Optional. --&gt;\r\n\t&lt;!-- &lt;description&gt;&lt;\/description&gt; --&gt;\r\n\r\n\t&lt;!-- Copyright information. Optional --&gt;\r\n\t&lt;!-- &lt;copyright&gt;&lt;\/copyright&gt; --&gt;\r\n\r\n\t&lt;!-- Publisher ID. Used if you're updating an application created prior to 1.5.3 --&gt;\r\n\t&lt;!-- &lt;publisherID&gt;&lt;\/publisherID&gt; --&gt;\r\n\r\n\t&lt;!-- Settings for the application's initial window. Required. --&gt;\r\n\t&lt;initialWindow&gt;\r\n\t\t&lt;!-- The main SWF or HTML file of the application. Required. --&gt;\r\n\t\t&lt;!-- Note: In Flash Builder, the SWF reference is set automatically. --&gt;\r\n\t\t&lt;content&gt;&#x5B;This value will be overwritten by Flash Builder in the output app.xml]&lt;\/content&gt;\r\n\t\t\r\n\t\t&lt;!-- The title of the main window. Optional. --&gt;\r\n\t\t&lt;!-- &lt;title&gt;&lt;\/title&gt; --&gt;\r\n\r\n\t\t&lt;!-- The type of system chrome to use (either &quot;standard&quot; or &quot;none&quot;). Optional. Default standard. --&gt;\r\n\t\t&lt;systemChrome&gt;none&lt;\/systemChrome&gt;\r\n\r\n\t\t&lt;!-- Whether the window is transparent. Only applicable when systemChrome is none. Optional. Default false. --&gt;\r\n\t\t&lt;transparent&gt;true&lt;\/transparent&gt;\r\n\r\n\t\t&lt;!-- Whether the window is initially visible. Optional. Default false. --&gt;\r\n\t\t&lt;!-- &lt;visible&gt;&lt;\/visible&gt; --&gt;\r\n\r\n\t\t&lt;!-- Whether the user can minimize the window. Optional. Default true. --&gt;\r\n\t\t&lt;!-- &lt;minimizable&gt;&lt;\/minimizable&gt; --&gt;\r\n\r\n\t\t&lt;!-- Whether the user can maximize the window. Optional. Default true. --&gt;\r\n\t\t&lt;!-- &lt;maximizable&gt;&lt;\/maximizable&gt; --&gt;\r\n\r\n\t\t&lt;!-- Whether the user can resize the window. Optional. Default true. --&gt;\r\n\t\t&lt;!-- &lt;resizable&gt;&lt;\/resizable&gt; --&gt;\r\n\r\n\t\t&lt;!-- The window's initial width. Optional. --&gt;\r\n\t\t&lt;!-- &lt;width&gt;&lt;\/width&gt; --&gt;\r\n\r\n\t\t&lt;!-- The window's initial height. Optional. --&gt;\r\n\t\t&lt;!-- &lt;height&gt;&lt;\/height&gt; --&gt;\r\n\r\n\t\t&lt;!-- The window's initial x position. Optional. --&gt;\r\n\t\t&lt;!-- &lt;x&gt;&lt;\/x&gt; --&gt;\r\n\r\n\t\t&lt;!-- The window's initial y position. Optional. --&gt;\r\n\t\t&lt;!-- &lt;y&gt;&lt;\/y&gt; --&gt;\r\n\r\n\t\t&lt;!-- The window's minimum size, specified as a width\/height pair, such as &quot;400 200&quot;. Optional. --&gt;\r\n\t\t&lt;!-- &lt;minSize&gt;&lt;\/minSize&gt; --&gt;\r\n\r\n\t\t&lt;!-- The window's initial maximum size, specified as a width\/height pair, such as &quot;1600 1200&quot;. Optional. --&gt;\r\n\t\t&lt;!-- &lt;maxSize&gt;&lt;\/maxSize&gt; --&gt;\r\n\t&lt;\/initialWindow&gt;\r\n\r\n\t&lt;!-- The subpath of the standard default installation location to use. Optional. --&gt;\r\n\t&lt;!-- &lt;installFolder&gt;&lt;\/installFolder&gt; --&gt;\r\n\r\n\t&lt;!-- The subpath of the Programs menu to use. (Ignored on operating systems without a Programs menu.) Optional. --&gt;\r\n\t&lt;!-- &lt;programMenuFolder&gt;&lt;\/programMenuFolder&gt; --&gt;\r\n\r\n\t&lt;!-- The icon the system uses for the application. For at least one resolution,\r\n\t\t specify the path to a PNG file included in the AIR package. Optional. --&gt;\r\n\t&lt;!-- &lt;icon&gt;\r\n\t\t&lt;image16x16&gt;&lt;\/image16x16&gt;\r\n\t\t&lt;image32x32&gt;&lt;\/image32x32&gt;\r\n\t\t&lt;image48x48&gt;&lt;\/image48x48&gt;\r\n\t\t&lt;image128x128&gt;&lt;\/image128x128&gt;\r\n\t&lt;\/icon&gt; --&gt;\r\n\r\n\t&lt;!-- Whether the application handles the update when a user double-clicks an update version\r\n\tof the AIR file (true), or the default AIR application installer handles the update (false).\r\n\tOptional. Default false. --&gt;\r\n\t&lt;!-- &lt;customUpdateUI&gt;&lt;\/customUpdateUI&gt; --&gt;\r\n\t\r\n\t&lt;!-- Whether the application can be launched when the user clicks a link in a web browser.\r\n\tOptional. Default false. --&gt;\r\n\t&lt;!-- &lt;allowBrowserInvocation&gt;&lt;\/allowBrowserInvocation&gt; --&gt;\r\n\r\n\t&lt;!-- Listing of file types for which the application can register. Optional. --&gt;\r\n\t&lt;!-- &lt;fileTypes&gt; --&gt;\r\n\r\n\t\t&lt;!-- Defines one file type. Optional. --&gt;\r\n\t\t&lt;!-- &lt;fileType&gt; --&gt;\r\n\r\n\t\t\t&lt;!-- The name that the system displays for the registered file type. Required. --&gt;\r\n\t\t\t&lt;!-- &lt;name&gt;&lt;\/name&gt; --&gt;\r\n\r\n\t\t\t&lt;!-- The extension to register. Required. --&gt;\r\n\t\t\t&lt;!-- &lt;extension&gt;&lt;\/extension&gt; --&gt;\r\n\t\t\t\r\n\t\t\t&lt;!-- The description of the file type. Optional. --&gt;\r\n\t\t\t&lt;!-- &lt;description&gt;&lt;\/description&gt; --&gt;\r\n\t\t\t\r\n\t\t\t&lt;!-- The MIME content type. --&gt;\r\n\t\t\t&lt;!-- &lt;contentType&gt;&lt;\/contentType&gt; --&gt;\r\n\t\t\t\r\n\t\t\t&lt;!-- The icon to display for the file type. Optional. --&gt;\r\n\t\t\t&lt;!-- &lt;icon&gt;\r\n\t\t\t\t&lt;image16x16&gt;&lt;\/image16x16&gt;\r\n\t\t\t\t&lt;image32x32&gt;&lt;\/image32x32&gt;\r\n\t\t\t\t&lt;image48x48&gt;&lt;\/image48x48&gt;\r\n\t\t\t\t&lt;image128x128&gt;&lt;\/image128x128&gt;\r\n\t\t\t&lt;\/icon&gt; --&gt;\r\n\t\t\t\r\n\t\t&lt;!-- &lt;\/fileType&gt; --&gt;\r\n\t&lt;!-- &lt;\/fileTypes&gt; --&gt;\r\n\r\n&lt;\/xml&gt;\r\n<\/pre>\n<p><strong>Main.mxml<\/strong><br \/>\nThe layout is a header and a body. The header is set up to be the move area for the window. he header is the top_hg HGroup on line 60. The body is the SWFHeaderBasic component on line 62. Here you could swap another body view easily.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;!--- \r\nMain view\r\n--&gt;\r\n&lt;s:Group xmlns:fx=&quot;http:\/\/ns.adobe.com\/mxml\/2009&quot; \r\n\t\t xmlns:s=&quot;library:\/\/ns.adobe.com\/flex\/spark&quot; \r\n\t\t xmlns:mx=&quot;library:\/\/ns.adobe.com\/flex\/mx&quot; \r\n\t\t xmlns:sf=&quot;http:\/\/www.spicefactory.org\/parsley&quot;\r\n\t\t \r\n\t\t width=&quot;100%&quot; height=&quot;100%&quot;\r\n\t\t xmlns:views=&quot;views.*&quot; \r\n\t\t xmlns:ui=&quot;ui.*&quot;\r\n\t\t &gt;\r\n\t&lt;fx:Script&gt;\r\n\t\t&lt;!&#x5B;CDATA&#x5B;\r\n\t\t\timport ui.ApplicationCloseButtonSkin;\r\n\t\t\t\/**\r\n\t\t\t * Called once Parsley framework has reflected.\r\n\t\t\t * *\/\r\n\t\t\t&#x5B;Init]\r\n\t\t\tpublic function parsleyInit():void\r\n\t\t\t{\r\n\t\t\t\ttop_hg.addEventListener(MouseEvent.MOUSE_DOWN, top_hg_onMouseDown);\r\n\t\t\t}\r\n\t\t\t\/**\r\n\t\t\t * Handler for top_hg MouseEvent.MOUSE_DOWN. Handles OS window move.\r\n\t\t\t * *\/\r\n\t\t\tprivate function top_hg_onMouseDown( evt:MouseEvent):void \r\n\t\t\t{ \r\n\t\t\t\tstage.nativeWindow.startMove(); \r\n\t\t\t}\r\n\t\t]]&gt;\r\n\t&lt;\/fx:Script&gt;\r\n\t&lt;fx:Declarations&gt;\r\n\t\t&lt;sf:Configure\/&gt;\r\n\t&lt;\/fx:Declarations&gt;\r\n\t&lt;fx:Style&gt;\r\n\t\t#appName_lbl {\r\n\t\t\tfont-weight:bold;\r\n\t\t\tcolor: #291F65;\r\n\t\t\tfont-size:18px;\r\n\t\t}\r\n\t\t#version_lbl {\r\n\t\t\tfont-weight:bold;\r\n\t\t\tcolor: #291F65;\r\n\t\t\tfont-size:10px;\r\n\t\t}\r\n\t&lt;\/fx:Style&gt;\r\n\t&lt;s:VGroup width=&quot;100%&quot; height=&quot;100%&quot;&gt;\r\n\t&lt;s:BorderContainer width=&quot;100%&quot; height=&quot;100%&quot;\r\n\t\t\t\t\t   cornerRadius=&quot;20&quot; borderWeight=&quot;3&quot; \r\n\t\t\t\t\t   borderColor=&quot;0x000000&quot; dropShadowVisible=&quot;true&quot;\r\n\t\t\t\t\t   backgroundColor=&quot;#858282&quot;&gt;\r\n\t\t&lt;s:VGroup  verticalAlign=&quot;middle&quot; width=&quot;100%&quot; height=&quot;100%&quot;\r\n\t\t\tpaddingLeft=&quot;6&quot; paddingRight=&quot;6&quot; paddingBottom=&quot;12&quot; \r\n\t\t\t\t&gt;\r\n\t\t\t&lt;!--- \r\n\t\t\tAppplication header and drag area.\r\n\t\t\t--&gt; \t\t\t\r\n\t\t\t&lt;s:HGroup id = &quot;top_hg&quot; width=&quot;100%&quot;  verticalAlign=&quot;middle&quot; paddingTop=&quot;12&quot;  &gt;\r\n\t\t\t\t&lt;s:HGroup  paddingLeft=&quot;5&quot; verticalAlign=&quot;middle&quot; horizontalAlign=&quot;left&quot; width=&quot;100%&quot;  gap=&quot;30&quot;&gt;\r\n\t\t\t\t\t&lt;mx:Image source=&quot;@Embed(source='..\/assets\/Adobe-swf_icon_40x40_published.png')&quot; \/&gt;\r\n\t\t\t\t\t&lt;s:Label id = &quot;appName_lbl&quot; text = &quot;SWF Header Inspection Tool&quot;\/&gt;\r\n\t\t\t\t&lt;\/s:HGroup&gt;\t\r\n\t\t\t\t&lt;s:HGroup  paddingRight=&quot;12&quot; verticalAlign=&quot;middle&quot; horizontalAlign=&quot;right&quot; width=&quot;100%&quot;  &gt;\r\n\t\t\t\t\t&lt;ui:ApplicationCloseButton  \r\n\t\t\t\t\t\tclick=&quot;NativeApplication.nativeApplication.exit()&quot; skinClass=&quot;ui.ApplicationCloseButtonSkin&quot;\/&gt;\r\n\t\t\t\t\t\r\n\t\t\t\t&lt;\/s:HGroup&gt;\t\t\t\r\n\t\t\r\n\t\t\t&lt;\/s:HGroup&gt;\r\n\t\t\t&lt;views:SWFHeaderBasic    width=&quot;100%&quot; height=&quot;100%&quot; \/&gt;\t\r\n\t\t\t&lt;s:Label id = &quot;version_lbl&quot; text = &quot;Version 1.00&quot;\/&gt;\r\n\t\t&lt;\/s:VGroup&gt;\r\n\r\n\t&lt;\/s:BorderContainer&gt;\r\n\t&lt;\/s:VGroup&gt;\t\r\n&lt;\/s:Group&gt;\r\n\r\n<\/pre>\n<p><strong>SWFHeaderBasic.mxml<\/strong><br \/>\nBody section for the application. You can easily plug in your own view to replace this one.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;!--- \r\nBasic view.\r\n--&gt;\r\n&lt;s:Group xmlns:fx=&quot;http:\/\/ns.adobe.com\/mxml\/2009&quot; \r\n\t\t xmlns:s=&quot;library:\/\/ns.adobe.com\/flex\/spark&quot; \r\n\t\t xmlns:sf=&quot;http:\/\/www.spicefactory.org\/parsley&quot;\r\n\t\t xmlns:mx=&quot;library:\/\/ns.adobe.com\/flex\/mx&quot; \r\n\t\t &gt;\r\n\t&lt;fx:Script&gt;\r\n\t\t&lt;!&#x5B;CDATA&#x5B;\r\n\t\t\timport events.LoadSwfUrlHeaderRequestEvent;\r\n\t\t\timport models.SWFHeaderModel;\r\n\t\t\timport mx.binding.utils.BindingUtils;\r\n\t\t\timport mx.binding.utils.ChangeWatcher;\r\n\t\t\timport mx.events.FlexEvent;\r\n\t\t\t\/**\r\n\t\t\t * File name extracted from url or path.\r\n\t\t\t * *\/\r\n\t\t\t&#x5B;Bindable]\r\n\t\t\tprivate var fileName:String = '';\r\n\t\t\t&#x5B;Inject]\r\n\t\t\t&#x5B;Bindable]\r\n\t\t\tpublic var model:SWFHeaderModel;\r\n\r\n\t\t\t&#x5B;MessageDispatcher]\r\n\t\t\tpublic var dispatcher:Function;\r\n\t\t\t\/**\r\n\t\t\t * Called once Parsley framework has reflected.\r\n\t\t\t * *\/\r\n\t\t\t&#x5B;Init]\r\n\t\t\tpublic function parsleyInit():void\r\n\t\t\t{\r\n\t\t\t\t\/\/ Bind the model changes from bytesLoaded in order to call a method.\r\n\t\t\t\tChangeWatcher.watch(model, &quot;bytesLoaded&quot;, updateProgressBar);\r\n\t\t\t\taddEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onDragEnterHandler);\r\n\t\t\t\taddEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onDragDropHandler);\r\n\t\t\t}\r\n\t\t\t\/**\r\n\t\t\t * Handler for the load_btn Mouse.Click event.\r\n\t\t\t * *\/\r\n\t\t\tprotected function load_btn_clickHandler(event:MouseEvent):void\r\n\t\t\t{\r\n\t\t\t\tfileName = url_ti.text.substr(   url_ti.text.lastIndexOf( '\/' ) + 1);\r\n\t\t\t\tdispatcher(new LoadSwfUrlHeaderRequestEvent (LoadSwfUrlHeaderRequestEvent.LOAD, url_ti.text));\r\n\t\t\t}\r\n\t\t\t\/**\r\n\t\t\t * Handler for the load_btn Mouse.Click event.\r\n\t\t\t * *\/\r\n\t\t\tprivate function updateProgressBar(bytesLoaded:Number):void\r\n\t\t\t{\r\n\t\t\t\t\/\/trace (className + &quot;.updateProgressBar(...) - model.bytesLoaded: &quot; + model.bytesLoaded);\t\r\n\t\t\t\t\/\/trace (className + &quot;.updateProgressBar(...) - model.bytesTotal: &quot; + model.bytesTotal);\t\r\n\t\t\t\tbar.setProgress(model.bytesLoaded,model.bytesTotal);\r\n\t\t\t\tvar pct:Number = Math.round((model.bytesLoaded\/model.bytesTotal) * 100);\r\n\t\t\t\tbar.label= &quot;Current Progress&quot; + &quot; &quot; + pct + &quot;%&quot;;\r\n\t\t\t}\r\n\t\t\t\/**\r\n\t\t\t * Handler for the NativeDragEvent.NATIVE_DRAG_ENTER event.\r\n\t\t\t * *\/\r\n\t\t\tprivate function onDragEnterHandler(e:NativeDragEvent):void\r\n\t\t\t{\r\n\t\t\t\t\/\/trace (className + &quot;.onDragEnterHandler(...)&quot;);\t\r\n\t\t\t\tif(e.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))\r\n\t\t\t\t{\r\n\t\t\t\t\t\/\/Get the array of File objects\r\n\t\t\t\t\tvar files:Array = e.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;\r\n\t\t\t\t\tvar file:File = File(files&#x5B;0]);\r\n\t\t\t\t\t\/\/Allow only one file as only supporting one in this application and soft check it is a swf file.\r\n\t\t\t\t\tif( files.length == 1 &amp;&amp; file.url.substr(file.url.length-4).toLowerCase() == &quot;.swf&quot; )\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t\/\/Triggers NativeDragEvent.NATIVE_DRAG_DROP event. \r\n\t\t\t\t\t\t\/\/This is when we see the drop icon.\r\n\t\t\t\t\t\tNativeDragManager.acceptDragDrop(this);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t\/**\r\n\t\t\t * Handler for the NativeDragEvent.NATIVE_DRAG_DROP event.\r\n\t\t\t * *\/\r\n\t\t\tprivate function onDragDropHandler(e:NativeDragEvent):void\r\n\t\t\t{\r\n\t\t\t\t\/\/trace (className + &quot;.onDragDropHandler(...)&quot;);\t\r\n\t\t\t\tvar files:Array = e.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;\r\n\t\t\t\tvar file:File = File(files&#x5B;0]);\r\n\t\t\t\t\/\/trace (className + &quot;.onDragDropHandler(...) - file.url:&quot; + file.url);\r\n\t\t\t\turl_ti.text = file.url;\r\n\t\t\t\tfileName = file.name;\r\n\t\t\t\t\/\/ Optional can initiate the load automatically.\r\n\t\t\t\tdispatcher(new LoadSwfUrlHeaderRequestEvent (LoadSwfUrlHeaderRequestEvent.LOAD, url_ti.text));\r\n\t\t\t}\r\n\t\t]]&gt;\r\n\t&lt;\/fx:Script&gt;\r\n\t&lt;fx:Declarations&gt;\r\n\t\t&lt;sf:Configure\/&gt;\r\n\t\t&lt;mx:NumberFormatter id=&quot;numberFormatter&quot; precision=&quot;0&quot;  useThousandsSeparator=&quot;true&quot; \/&gt;\r\n\t&lt;\/fx:Declarations&gt;\r\n\t&lt;!--- \r\n\tCreate NativeDrag target with BorderContainer\r\n\t--&gt; \r\n\t&lt;s:BorderContainer \r\n\t\t\t\twidth=&quot;100%&quot; height=&quot;100%&quot;\r\n\t\t\t\t\t   borderAlpha=&quot;0&quot;\t\r\n\t\t\t\t\t   backgroundColor=&quot;0xffffff&quot;\r\n\t\t\t\t\t   &gt;\r\n\t&lt;s:VGroup verticalAlign=&quot;top&quot;  horizontalAlign=&quot;center&quot; width=&quot;100%&quot; height=&quot;100%&quot;   \r\n\t\t\t   paddingTop=&quot;10&quot;\r\n\t\t\t   &gt;\r\n\t\t&lt;s:HGroup &gt;\r\n\t\t\t&lt;s:Label  text=&quot;SWF URL:&quot; paddingTop=&quot;6&quot; \/&gt;\r\n\t\t\t&lt;s:VGroup &gt;\r\n\t\t\t\t&lt;s:HGroup  verticalAlign=&quot;middle&quot;&gt;\r\n\t\t\t\t&lt;s:TextInput id=&quot;url_ti&quot; text=&quot;Enter swf http url or drag from desktop&quot; width=&quot;294&quot; \/&gt;\r\n\t\t\t\t&lt;s:Button  label=&quot;Load SWF&quot; id=&quot;load_btn&quot; click=&quot;load_btn_clickHandler(event)&quot;\/&gt;\t\r\n\t\t\t\t&lt;\/s:HGroup&gt;\r\n\t\t\t\t&lt;!--- \r\n\t\t\t\tProgress bar for slow loads such as the internet.\r\n\t\t\t\t--&gt; \t\t\r\n\t\t\t\t&lt;mx:ProgressBar id=&quot;bar&quot;   labelPlacement=&quot;bottom&quot; minimum=&quot;0&quot; visible=&quot;true&quot; maximum=&quot;100&quot;\r\n\t\t\t\t\t\t\t\tcolor=&quot;0x323232&quot; \r\n\t\t\t\t\t\t\t\tlabel=&quot;Current Progress 0%&quot; direction=&quot;right&quot; \r\n\t\t\t\t\t\t\t\tmode=&quot;manual&quot; width=&quot;100%&quot;\/&gt;\r\n\t\t\t&lt;\/s:VGroup&gt;\r\n\t\t&lt;\/s:HGroup&gt;\r\n\t\t&lt;!--- \r\n\t\tThe result values\r\n\t\t--&gt; \r\n\t\t&lt;mx:Form width=&quot;100%&quot; height=&quot;100%&quot;       &gt;\r\n\t\t\t&lt;mx:FormItem label=&quot;SWF File name: &quot;&gt;\r\n\t\t\t\t&lt;s:Label color=&quot;0x000000&quot; text=&quot;{fileName}&quot;\/&gt;\r\n\t\t\t&lt;\/mx:FormItem&gt;\r\n\t\t\t&lt;mx:FormItem label=&quot;Flash player version: &quot;&gt;\r\n\t\t\t\t&lt;s:Label color=&quot;0x000000&quot; text=&quot;{numberFormatter.format(model.swfHeader_vo.swfVersion)}&quot;\/&gt;\r\n\t\t\t&lt;\/mx:FormItem&gt;\r\n\t\t\t&lt;s:HGroup&gt;\r\n\t\t\t\t&lt;mx:FormItem label=&quot;Size uncompressed: &quot;&gt;\r\n\t\t\t\t\t&lt;s:Label color=&quot;0x000000&quot; text=&quot;{numberFormatter.format(model.swfHeader_vo.sizeUncompressed)}&quot;\/&gt;\r\n\t\t\t\t&lt;\/mx:FormItem&gt;\r\n\t\t\t\t&lt;mx:FormItem label=&quot;Compressed: &quot;&gt;\r\n\t\t\t\t\t&lt;s:Label color=&quot;0x000000&quot; text=&quot;{numberFormatter.format(model.swfHeader_vo.sizeCompressed)}&quot;\/&gt;\r\n\t\t\t\t&lt;\/mx:FormItem&gt;\t\t\t\r\n\t\t\t&lt;\/s:HGroup&gt;\r\n\t\t\t&lt;mx:FormItem label=&quot;Frame rate: &quot;&gt;\r\n\t\t\t\t&lt;s:Label color=&quot;0x000000&quot; text=&quot;{numberFormatter.format(model.swfHeader_vo.frameRate)}&quot;\/&gt;\r\n\t\t\t&lt;\/mx:FormItem&gt;\r\n\t\t\t&lt;mx:FormItem label=&quot;Total frames: &quot;&gt;\r\n\t\t\t\t&lt;s:Label color=&quot;0x000000&quot; text=&quot;{numberFormatter.format(model.swfHeader_vo.totalFrames)}&quot;\/&gt;\r\n\t\t\t&lt;\/mx:FormItem&gt;\r\n\t\t\t&lt;mx:FormItem label=&quot;Width: &quot;&gt;\r\n\t\t\t\t&lt;s:Label  color=&quot;0x000000&quot; text=&quot;{numberFormatter.format(model.swfHeader_vo.width)}&quot;\/&gt;\r\n\t\t\t&lt;\/mx:FormItem&gt;\r\n\t\t\t&lt;mx:FormItem label=&quot;Height: &quot;&gt;\r\n\t\t\t\t&lt;s:Label color=&quot;0x000000&quot; text=&quot;{numberFormatter.format(model.swfHeader_vo.height)}&quot;\/&gt;\r\n\t\t\t&lt;\/mx:FormItem&gt;\r\n\t\t&lt;\/mx:Form&gt;\r\n\t&lt;\/s:VGroup&gt;\r\n\t&lt;\/s:BorderContainer&gt;\r\n&lt;\/s:Group&gt;\r\n<\/pre>\n<p><strong>ApplicationCloseButton.as<\/strong><br \/>\nOwn version of the spark Button class.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage ui\r\n{\r\n\timport spark.components.Button;\r\n\t\/**\r\n\t * Button to close the application\r\n\t * *\/\r\n\tpublic class ApplicationCloseButton extends Button\r\n\t{\r\n\t\tpublic function ApplicationCloseButton()\r\n\t\t{\r\n\t\t\tsuper();\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>ApplicationCloseButtonSkin.mxml<\/strong><br \/>\nSkin for the application close button class, ApplicationCloseButton. I had some trouble with the edges of the images causing a repeating state change on rollover. I solved this by making a transparent background on line 29 a few pixels larger than the bitmaps. The bitmaps then had their verticalCenter and  horizontalCenter properities set to zero to keep them in the middle. See lines 34 and 36.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;!--- \r\nSkin for ui.ApplicationCloseButton\r\n--&gt;\r\n&lt;s:SparkSkin xmlns:fx=&quot;http:\/\/ns.adobe.com\/mxml\/2009&quot;\r\n\t\t\t xmlns:s=&quot;library:\/\/ns.adobe.com\/flex\/spark&quot;\r\n\t\t\t xmlns:fb=&quot;http:\/\/ns.adobe.com\/flashbuilder\/2009&quot;\r\n\t\t\t \r\n\t\t\t alpha.disabled=&quot;0.5&quot;&gt;\r\n\t\r\n\t&lt;!-- host component --&gt;\r\n\t&lt;fx:Metadata&gt;\r\n\t\t&lt;!&#x5B;CDATA&#x5B;\r\n\t\t\/* @copy spark.skins.spark.ApplicationSkin#hostComponent \t*\/\r\n\t\t&#x5B;HostComponent(&quot;ui.ApplicationCloseButton&quot;)]\r\n\t\t]]&gt;\r\n\t&lt;\/fx:Metadata&gt;\r\n\t\r\n\t&lt;!-- states --&gt;\r\n\t&lt;s:states&gt;\r\n\t\t&lt;s:State name=&quot;up&quot; \/&gt;\r\n\t\t&lt;s:State name=&quot;over&quot; \/&gt;\r\n\t\t&lt;s:State name=&quot;down&quot; \/&gt;\r\n\t\t&lt;s:State name=&quot;disabled&quot; \/&gt;\r\n\t&lt;\/s:states&gt;\r\n\t&lt;!--- \r\n\tHit area.\r\n\t--&gt;\t\r\n\t&lt;s:Rect  left=&quot;0&quot; right=&quot;0&quot; top=&quot;0&quot; bottom=&quot;0&quot;  width=&quot;34&quot; height=&quot;34&quot;&gt;\r\n\t\t&lt;s:fill&gt;\r\n\t\t\t&lt;s:SolidColor color=&quot;0xffffff&quot; alpha=&quot;0&quot; \/&gt;\r\n\t\t&lt;\/s:fill&gt;\t\r\n\t&lt;\/s:Rect&gt;\r\n\t&lt;s:BitmapImage  verticalCenter=&quot;0&quot;  horizontalCenter=&quot;0&quot; source=&quot;@Embed('..\/assets\/red_glossy_close_up_button_published.png')&quot; \r\n\t\t\t\t   includeIn=&quot;up, disabled, down &quot;\/&gt;\r\n\t&lt;s:BitmapImage verticalCenter=&quot;0&quot;  horizontalCenter=&quot;0&quot;  source=&quot;@Embed('..\/assets\/green_glossy_close_up_button_published.png')&quot; \r\n\t\t\t\t   includeIn=&quot;over&quot;\/&gt;\r\n\t\r\n&lt;\/s:SparkSkin&gt;\r\n<\/pre>\n<p><strong>ApplicationModel.as<\/strong><br \/>\nI could have merged the two models, but as a practice in Parsley frameworks, I create an ApplicationModel by default.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage models\r\n{\r\n\t\/**\r\n\t * Application model.\r\n\t * *\/\r\n\tpublic class ApplicationModel\r\n\t{\r\n\r\n\t}\r\n}\r\n<\/pre>\n<p>[ad name=&#8221;Google Adsense&#8221;]<br \/>\n<strong>SWFHeaderModel.as<\/strong><br \/>\nThe model containing all the bound data. Flex binding is magnificent for creating model-view-controller solutions. <\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage models\r\n{\r\n\timport vo.SWFHeader_vo;\r\n\t\/**\r\n\t * Model for the SWF header information.\r\n\t * *\/\r\n\tpublic class SWFHeaderModel\r\n\t{\r\n\t\t\/**\r\n\t\t * Swf header field values.\r\n\t\t * *\/\r\n\t\t&#x5B;Bindable]\r\n\t\tpublic var swfHeader_vo:SWFHeader_vo;\r\n\t\t\/**\r\n\t\t * Nest the ApplicationModel.\r\n\t\t * *\/\t\t\r\n\t\t&#x5B;Inject]\r\n\t\t&#x5B;Bindable]\r\n\t\tpublic var applicationModel:ApplicationModel;\r\n\t\t\/**\r\n\t\t * Bytes loaded.\r\n\t\t * *\/\r\n\t\t&#x5B;Bindable]\r\n\t\tpublic var bytesLoaded:Number;\r\n\t\t\/**\r\n\t\t * Total bytes to load.\r\n\t\t * *\/\t\t\r\n\t\t&#x5B;Bindable]\r\n\t\tpublic var bytesTotal:Number;\r\n\t\t\/**\r\n\t\t * Initialize model values.\r\n\t\t * *\/\t\t\r\n\t\tpublic function SWFHeaderModel()\r\n\t\t{\r\n\t\t\tswfHeader_vo = new SWFHeader_vo();\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>ApplicationController.as<\/strong><br \/>\nI could have created a controller just for the SWF header if I wanted a separate model-view-controller  for SWF header decoupled from the application. <\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage controllers\r\n{\r\n\timport events.LoadSwfUrlHeaderRequestEvent;\r\n\timport events.SWFHeaderLoaderCompleteEvent;\r\n\timport events.SWFHeaderLoaderErrorEvent;\r\n\timport events.SWFHeaderLoaderProgressEvent;\r\n\timport flash.net.URLRequest;\r\n\timport models.SWFHeaderModel;\r\n\timport mx.controls.Alert;\r\n\timport swf.SWFHeaderLoader;\r\n\timport vo.SWFHeader_vo;\r\n\t\/**\r\n\t * Application controller\r\n\t * *\/\r\n\tpublic class ApplicationController\r\n\t{\r\n\t\t\/**\r\n\t\t * Toggle to indicate if an Alert error is being shown. All loading errors are \r\n\t\t * routed to one method and so if there are more than one per SWFHeaderLoader.load\r\n\t\t * request, this prevents multiple Alert popups.\r\n\t\t * @see swfHeaderErroMessageHandler\r\n\t\t * *\/\r\n\t\tprivate var showingSwfLoadError:Boolean = false;\r\n\t\t\/**\r\n\t\t * The SWFHeaderLoader\r\n\t\t * *\/\r\n\t\t&#x5B;Inject]\r\n\t\tpublic var swfHeaderLoader:SWFHeaderLoader;\r\n\t\t\/**\r\n\t\t * The model for MVC.\r\n\t\t * *\/\r\n\t\t&#x5B;Inject]\r\n\t\t&#x5B;Bindable]\r\n\t\tpublic var model:SWFHeaderModel;\r\n\t\t\/**\r\n\t\t * Information Alert dialog title.\r\n\t\t * *\/\r\n\t\tprivate var lang_info_alert_title:String = &quot;Attention&quot;;\r\n\t\t\/**\r\n\t\t * Message when file name does not contain a .swf extension.\r\n\t\t * *\/\r\n\t\tprivate var lang_tool_requires_swf:String = &quot;Tool is designed for Flash Movie \\&quot;.swf\\&quot; files&quot;;\r\n\t\t\/**\r\n\t\t * Message when swf file could not be loaded for any reason.\r\n\t\t * *\/\r\n\t\tprivate var lang_unable_to_load_swf:String = &quot;Sorry, unable to load the file.&quot;;\r\n\t\t\/**\r\n\t\t * Handler for LoadSwfUrlHeaderRequestEvent. Validate file extension. Load swf.\r\n\t\t * *\/\r\n\t\t&#x5B;MessageHandler]\r\n\t\tpublic function swfUrlLoadRequestMessageHandler( message : LoadSwfUrlHeaderRequestEvent ):void\r\n\t\t{\r\n\t\t\tmodel.swfHeader_vo = new SWFHeader_vo();\r\n\t\t\t\/\/ File url does not have a .swf at end.\r\n\t\t\tif ( message.swf_url.substr(message.swf_url.length-4).toLowerCase() != &quot;.swf&quot;  )\r\n\t\t\t{\r\n\t\t\t\tAlert.show(lang_tool_requires_swf ,lang_info_alert_title);\r\n\t\t\t}\r\n\t\t\t\/\/ File url has a .swf at end.\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tshowingSwfLoadError = false;\r\n\t\t\t\tswfHeaderLoader.load(message.swf_url);\r\n\t\t\t}\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Handler for SWFHeaderLoaderProgressEvent.\r\n\t\t * *\/\r\n\t\t&#x5B;MessageHandler]\r\n\t\tpublic function swfHeaderProgressMessageHandler( message : SWFHeaderLoaderProgressEvent ):void\r\n\t\t{\r\n\t\t\tmodel.bytesTotal = message.bytesTotal;\r\n\t\t\tmodel.bytesLoaded = message.bytesLoaded;\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Handler for SWFHeaderLoaderCompleteEvent.\r\n\t\t * *\/\r\n\t\t&#x5B;MessageHandler]\r\n\t\tpublic function swfHeaderLoadedMessageHandler( message : SWFHeaderLoaderCompleteEvent ):void\r\n\t\t{\r\n\t\t\tmodel.swfHeader_vo = message.swfHeader_vo;\r\n\t\t}\r\n\t\t\/**\r\n\t\t * Handler for SWFHeaderLoaderErrorEvent.\r\n\t\t * *\/\r\n\t\t&#x5B;MessageHandler]\r\n\t\tpublic function swfHeaderErroMessageHandler( message : SWFHeaderLoaderErrorEvent ):void\r\n\t\t{\r\n\t\t\tif (!showingSwfLoadError)\r\n\t\t\t{\r\n\t\t\t\tshowingSwfLoadError = true;\r\n\t\t\t\tAlert.show(lang_unable_to_load_swf,lang_info_alert_title);\r\n\t\t\t}\r\n\t\t}\t\t\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>LoadSwfUrlHeaderRequestEvent.as<\/strong><br \/>\nEvent handler for requests to load a swf. Note how Parsley simplifies the event code.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage events\r\n{\r\n\timport flash.events.Event;\r\n\t\/**\r\n\t * Request the loading of a swf file.\r\n\t * *\/\r\n\tpublic class LoadSwfUrlHeaderRequestEvent extends Event\r\n\t{\r\n\t\tpublic static const LOAD:String = &quot;event.load&quot;;\r\n\t\tpublic var swf_url:String;\r\n\t\tpublic function LoadSwfUrlHeaderRequestEvent(type:String, swf_url:String, bubbles:Boolean=false, cancelable:Boolean=false)\r\n\t\t{\r\n\t\t\tsuper(type, bubbles, cancelable);\r\n\t\t\tthis.swf_url = swf_url;\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>SWFHeaderLoaderProgressEvent.as<\/strong><br \/>\nFor monitoring the loading particularly when over the internet.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage events\r\n{\r\n\timport flash.events.Event;\r\n\t\/**\r\n\t * Progress of loading a swf file.\r\n\t * *\/\t\r\n\tpublic class SWFHeaderLoaderProgressEvent extends Event\r\n\t{\r\n\t\tpublic static const PROGRESS:String = &quot;event_SWFHeaderLoaderEvent_progress&quot;;\r\n\t\t\/**\r\n\t\t * Bytes loaded.\r\n\t\t * *\/\t\r\n\t\tpublic var bytesLoaded:Number;\r\n\t\t\/**\r\n\t\t * Total bytes to load.\r\n\t\t * *\/\t\t\r\n\t\tpublic var bytesTotal:Number;\r\n\t\tpublic function SWFHeaderLoaderProgressEvent(type:String, bytesLoaded:Number, bytesTotal:Number, bubbles:Boolean=false, cancelable:Boolean=false)\r\n\t\t{\r\n\t\t\tsuper(type, bubbles, cancelable);\r\n\t\t\tthis.bytesLoaded = bytesLoaded;\r\n\t\t\tthis.bytesTotal = bytesTotal;\r\n\t\t\t\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>SWFHeaderLoaderCompleteEvent.as<\/strong><br \/>\nWhen an SWF is completely loaded. You may want to redesign to stop once the header is loaded. However I had thought it might be nice to show the SWF at one point or proceed to extract other information.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage events\r\n{\r\n\timport flash.events.Event;\r\n\timport vo.SWFHeader_vo;\r\n\t\/**\r\n\t * Completion of loading a swf file.\r\n\t * *\/\r\n\tpublic class SWFHeaderLoaderCompleteEvent extends Event\r\n\t{\r\n\t\tpublic static const COMPLETE:String = &quot;event_SWFHeaderLoaderEvent_complete&quot;;\r\n\t\t\/**\r\n\t\t * Swf file header data.\r\n\t\t * *\/\t\r\n\t\tpublic var swfHeader_vo:SWFHeader_vo;\r\n\t\tpublic function SWFHeaderLoaderCompleteEvent(type:String, swfHeader_vo:SWFHeader_vo, bubbles:Boolean=false, cancelable:Boolean=false)\r\n\t\t{\r\n\t\t\tsuper(type, bubbles, cancelable);\r\n\t\t\tthis.swfHeader_vo = swfHeader_vo;\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p><strong>SWFHeaderLoaderErrorEvent.as<\/strong><br \/>\nErrors in loading the Swf file.<\/p>\n<pre class=\"brush: as3; title: ; wrap-lines: false; notranslate\" title=\"\">\r\npackage events\r\n{\r\n\timport flash.events.Event;\r\n\t\/**\r\n\t * Errors from loading a swf file.\r\n\t * *\/\r\n\tpublic class SWFHeaderLoaderErrorEvent extends Event\r\n\t{\r\n\t\tpublic static const SECURITY_ERROR:String = &quot;event_SWFHeaderLoaderEvent_security&quot;;\r\n\t\tpublic static const HTTP_ERROR:String = &quot;event_SWFHeaderLoaderEvent_HTTP&quot;;\r\n\t\tpublic static const IO_ERROR:String = &quot;event_SWFHeaderLoaderEvent_IO&quot;;\r\n\t\tpublic function SWFHeaderLoaderErrorEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)\r\n\t\t{\r\n\t\t\tsuper(type, bubbles, cancelable);\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I was asked to look for open source tools to read the basic information contained in a Flash swf file. Most of the items you find are for reverse engineering swf files. In the search process I found two sources to parse the swf file header. The first was a php script written by Carlos [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[19,20,47,9,55],"class_list":["post-1204","post","type-post","status-publish","format-standard","hentry","category-general","tag-actionscript","tag-air","tag-bordercontainer","tag-flex","tag-parsley"],"_links":{"self":[{"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/posts\/1204","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/comments?post=1204"}],"version-history":[{"count":27,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/posts\/1204\/revisions"}],"predecessor-version":[{"id":3692,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/posts\/1204\/revisions\/3692"}],"wp:attachment":[{"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/media?parent=1204"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/categories?post=1204"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lonhosford.com\/lonblog\/wp-json\/wp\/v2\/tags?post=1204"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}