Repository: flex-utilities Updated Branches: refs/heads/develop a338ddf1f -> 2454c94f4
utility that will check MD5s of installer downloads Project: http://git-wip-us.apache.org/repos/asf/flex-utilities/repo Commit: http://git-wip-us.apache.org/repos/asf/flex-utilities/commit/2454c94f Tree: http://git-wip-us.apache.org/repos/asf/flex-utilities/tree/2454c94f Diff: http://git-wip-us.apache.org/repos/asf/flex-utilities/diff/2454c94f Branch: refs/heads/develop Commit: 2454c94f4d04039ee20128301ed21305e9fd6a05 Parents: a338ddf Author: Alex Harui <aha...@apache.org> Authored: Tue Jul 29 09:01:50 2014 -0700 Committer: Alex Harui <aha...@apache.org> Committed: Tue Jul 29 09:02:08 2014 -0700 ---------------------------------------------------------------------- MD5Checker/build.xml | 127 ++++++++++ MD5Checker/src/MD5Checker-app.xml | 250 ++++++++++++++++++++ MD5Checker/src/MD5Checker.mxml | 414 +++++++++++++++++++++++++++++++++ 3 files changed, 791 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/2454c94f/MD5Checker/build.xml ---------------------------------------------------------------------- diff --git a/MD5Checker/build.xml b/MD5Checker/build.xml new file mode 100644 index 0000000..cce74a9 --- /dev/null +++ b/MD5Checker/build.xml @@ -0,0 +1,127 @@ +<?xml version="1.0"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> + +<project name="MD5Checker" basedir="." default="main"> + + <!--load environment variables prefixed with env --> + <property environment="env"/> + + <!-- + Properties are immutable so value frozen first time property is set. + If FLEX_HOME is not set with -DFLEX_HOME=/path/to/flex/sdk on the ant command line + use the environment variable, if it exists. Else if windows, use FLEX_HOME_WIN + else use FLEX_HOME_MAC, which are both defined in build.properties. + --> + <condition property="FLEX_HOME" value="${env.FLEX_HOME}"> + <isset property="env.FLEX_HOME" /> + </condition> + <condition property="AIR_HOME" value="${env.AIR_HOME}"> + <isset property="env.AIR_HOME" /> + </condition> + + <condition property="theOS" value="Windows"> + <os family="windows"/> + </condition> + <condition property="theOS" value="Mac"> + <os family="mac"/> + </condition> + <condition property="isMac" value="Mac"> + <os family="mac"/> + </condition> + + <condition property="and_success" value="success" > + <and> + <matches string="foobar" pattern=".*bar" /> + <isset property="env.FLEX_HOME" /> + </and> + </condition> + + <condition property="and_failure" value="success" > + <and> + <matches string="foobar" pattern=".*bar" /> + <isset property="env.NONEXISTANT" /> + </and> + </condition> + + <condition property="or_success" value="success" > + <or> + <matches string="foobar" pattern=".*bar" /> + <isset property="env.NONEXISTANT" /> + </or> + </condition> + + <condition property="or_failure" value="success" > + <or> + <matches string="foobar" pattern=".*fred" /> + <isset property="env.NONEXISTANT" /> + </or> + </condition> + + <condition property="should_fail" value="success" > + <and> + <matches string="foobar" pattern=".*bar" /> + <not> + <isset property="env.FLEX_HOME" /> + </not> + </and> + </condition> + + <target name="main" depends="build"> + <exec executable="${AIR_HOME}/bin/adl.exe" osfamily="windows" resultproperty="md5result" failonerror="false"> + <arg value="-runtime"/> + <arg value="${AIR_HOME}/runtimes/air/win"/> + <arg value="${basedir}/src/MD5Checker-app.xml"/> + </exec> + <exec executable="${AIR_HOME}/bin/adl" osfamily="mac" resultproperty="md5result" failonerror="false"> + <arg value="-runtime"/> + <arg value="${AIR_HOME}/runtimes/air/mac"/> + <arg value="${basedir}/src/MD5Checker-app.xml"/> + <arg value="--" /> + <arg value="-log=${basedir}/MD5CheckerLog.txt"/> + </exec> + <loadfile property="md5log" srcfile="${basedir}/MD5CheckerLog.txt" /> + <echo>${md5log}</echo> + <fail message="MD5's changed!" > + <condition> + <not> + <equals arg1="0" arg2="${md5result}" /> + </not> + </condition> + </fail> + </target> + + <target name="load-task" > + <!-- load the <mxmlc> task; we can't do this at the <project> level --> + <!-- because targets that run before flexTasks.jar gets built would fail --> + <taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/lib/flexTasks.jar"/> + </target> + + <target name="build" depends="load-task" description="compile it"> + + <!-- compile the basic tests --> + <mxmlc fork="true" + file="${basedir}/src/MD5Checker.mxml"> + <jvmarg line="-Xms64m -Xmx384m -ea -Dapple.awt.UIElement=true"/> + <load-config filename="${FLEX_HOME}/frameworks/air-config.xml"/> + <source-path path-element="${basedir}/../ant_on_air/src" /> + </mxmlc> + </target> + +</project> http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/2454c94f/MD5Checker/src/MD5Checker-app.xml ---------------------------------------------------------------------- diff --git a/MD5Checker/src/MD5Checker-app.xml b/MD5Checker/src/MD5Checker-app.xml new file mode 100644 index 0000000..b3f24b1 --- /dev/null +++ b/MD5Checker/src/MD5Checker-app.xml @@ -0,0 +1,250 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + --> +<application xmlns="http://ns.adobe.com/air/application/3.1"> + +<!-- Adobe AIR Application Descriptor File Template. + + Specifies parameters for identifying, installing, and launching AIR applications. + + xmlns - The Adobe AIR namespace: http://ns.adobe.com/air/application/3.1 + The last segment of the namespace specifies the version + of the AIR runtime required for this application to run. + + minimumPatchLevel - The minimum patch level of the AIR runtime required to run + the application. Optional. +--> + + <!-- A universally unique application identifier. Must be unique across all AIR applications. + Using a reverse DNS-style name as the id is recommended. (Eg. com.example.ExampleApplication.) Required. --> + <id>MD5Checker</id> + + <!-- Used as the filename for the application. Required. --> + <filename>MD5Checker</filename> + + <!-- The name that is displayed in the AIR application installer. + May have multiple values for each language. See samples or xsd schema file. Optional. --> + <name>MD5Checker</name> + + <!-- A string value of the format <0-999>.<0-999>.<0-999> that represents application version which can be used to check for application upgrade. + Values can also be 1-part or 2-part. It is not necessary to have a 3-part value. + An updated version of application must have a versionNumber value higher than the previous version. Required for namespace >= 2.5 . --> + <versionNumber>0.0.0</versionNumber> + + <!-- A string value (such as "v1", "2.5", or "Alpha 1") that represents the version of the application, as it should be shown to users. Optional. --> + <!-- <versionLabel></versionLabel> --> + + <!-- Description, displayed in the AIR application installer. + May have multiple values for each language. See samples or xsd schema file. Optional. --> + <!-- <description></description> --> + + <!-- Copyright information. Optional --> + <!-- <copyright></copyright> --> + + <!-- Publisher ID. Used if you're updating an application created prior to 1.5.3 --> + <!-- <publisherID></publisherID> --> + + <!-- Settings for the application's initial window. Required. --> + <initialWindow> + <!-- The main SWF or HTML file of the application. Required. --> + <!-- Note: In Flash Builder, the SWF reference is set automatically. --> + <content>MD5Checker.swf</content> + + <!-- The title of the main window. Optional. --> + <!-- <title></title> --> + + <!-- The type of system chrome to use (either "standard" or "none"). Optional. Default standard. --> + <!-- <systemChrome></systemChrome> --> + + <!-- Whether the window is transparent. Only applicable when systemChrome is none. Optional. Default false. --> + <!-- <transparent></transparent> --> + + <!-- Whether the window is initially visible. Optional. Default false. --> + <!-- <visible></visible> --> + + <!-- Whether the user can minimize the window. Optional. Default true. --> + <!-- <minimizable></minimizable> --> + + <!-- Whether the user can maximize the window. Optional. Default true. --> + <!-- <maximizable></maximizable> --> + + <!-- Whether the user can resize the window. Optional. Default true. --> + <!-- <resizable></resizable> --> + + <!-- The window's initial width in pixels. Optional. --> + <!-- <width></width> --> + + <!-- The window's initial height in pixels. Optional. --> + <!-- <height></height> --> + + <!-- The window's initial x position. Optional. --> + <!-- <x></x> --> + + <!-- The window's initial y position. Optional. --> + <!-- <y></y> --> + + <!-- The window's minimum size, specified as a width/height pair in pixels, such as "400 200". Optional. --> + <!-- <minSize></minSize> --> + + <!-- The window's initial maximum size, specified as a width/height pair in pixels, such as "1600 1200". Optional. --> + <!-- <maxSize></maxSize> --> + + <!-- The initial aspect ratio of the app when launched (either "portrait" or "landscape"). Optional. Mobile only. Default is the natural orientation of the device --> + + <!-- <aspectRatio></aspectRatio> --> + + <!-- Whether the app will begin auto-orienting on launch. Optional. Mobile only. Default false --> + + <!-- <autoOrients></autoOrients> --> + + <!-- Whether the app launches in full screen. Optional. Mobile only. Default false --> + + <!-- <fullScreen></fullScreen> --> + + <!-- The render mode for the app (either auto, cpu, gpu, or direct). Optional. Default auto --> + + <!-- <renderMode></renderMode> --> + + <!-- Whether or not to pan when a soft keyboard is raised or lowered (either "pan" or "none"). Optional. Defaults "pan." --> + <!-- <softKeyboardBehavior></softKeyboardBehavior> --> + <autoOrients>false</autoOrients> + <fullScreen>false</fullScreen> + <visible>false</visible> + </initialWindow> + + <!-- We recommend omitting the supportedProfiles element, --> + <!-- which in turn permits your application to be deployed to all --> + <!-- devices supported by AIR. If you wish to restrict deployment --> + <!-- (i.e., to only mobile devices) then add this element and list --> + <!-- only the profiles which your application does support. --> + <!-- <supportedProfiles>desktop extendedDesktop mobileDevice extendedMobileDevice</supportedProfiles> --> + + <!-- The subpath of the standard default installation location to use. Optional. --> + <!-- <installFolder></installFolder> --> + + <!-- The subpath of the Programs menu to use. (Ignored on operating systems without a Programs menu.) Optional. --> + <!-- <programMenuFolder></programMenuFolder> --> + + <!-- The icon the system uses for the application. For at least one resolution, + specify the path to a PNG file included in the AIR package. Optional. --> + <!-- <icon> + <image16x16></image16x16> + <image32x32></image32x32> + <image36x36></image36x36> + <image48x48></image48x48> + <image57x57></image57x57> + <image72x72></image72x72> + <image114x114></image114x114> + <image128x128></image128x128> + </icon> --> + + <!-- Whether the application handles the update when a user double-clicks an update version + of the AIR file (true), or the default AIR application installer handles the update (false). + Optional. Default false. --> + <!-- <customUpdateUI></customUpdateUI> --> + + <!-- Whether the application can be launched when the user clicks a link in a web browser. + Optional. Default false. --> + <!-- <allowBrowserInvocation></allowBrowserInvocation> --> + + <!-- Listing of file types for which the application can register. Optional. --> + <!-- <fileTypes> --> + + <!-- Defines one file type. Optional. --> + <!-- <fileType> --> + + <!-- The name that the system displays for the registered file type. Required. --> + <!-- <name></name> --> + + <!-- The extension to register. Required. --> + <!-- <extension></extension> --> + + <!-- The description of the file type. Optional. --> + <!-- <description></description> --> + + <!-- The MIME content type. --> + <!-- <contentType></contentType> --> + + <!-- The icon to display for the file type. Optional. --> + <!-- <icon> + <image16x16></image16x16> + <image32x32></image32x32> + <image48x48></image48x48> + <image128x128></image128x128> + </icon> --> + + <!-- </fileType> --> + <!-- </fileTypes> --> + + <!-- iOS specific capabilities --> + <!-- <iPhone> --> + <!-- A list of plist key/value pairs to be added to the application Info.plist --> + <!-- <InfoAdditions> + <![CDATA[ + <key>UIDeviceFamily</key> + <array> + <string>1</string> + <string>2</string> + </array> + <key>UIStatusBarStyle</key> + <string>UIStatusBarStyleBlackOpaque</string> + <key>UIRequiresPersistentWiFi</key> + <string>YES</string> + ]]> + </InfoAdditions> --> + <!-- A list of plist key/value pairs to be added to the application Entitlements.plist --> + <!-- <Entitlements> + <![CDATA[ + <key>keychain-access-groups</key> + <array> + <string></string> + <string></string> + </array> + ]]> + </Entitlements> --> + <!-- Display Resolution for the app (either "standard" or "high"). Optional. Default "standard" --> + <!-- <requestedDisplayResolution></requestedDisplayResolution> --> + <!-- </iPhone> --> + + <!-- Specify Android specific tags that get passed to AndroidManifest.xml file. --> + <!--<android> --> + <!-- <manifestAdditions> + <![CDATA[ + <manifest android:installLocation="auto"> + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> + <uses-feature android:required="true" android:name="android.hardware.touchscreen.multitouch"/> + <application android:enabled="true"> + <activity android:excludeFromRecents="false"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> + </manifest> + ]]> + </manifestAdditions> --> + <!-- Color depth for the app (either "32bit" or "16bit"). Optional. Default 16bit before namespace 3.0, 32bit after --> + <!-- <colorDepth></colorDepth> --> + <!-- </android> --> + <!-- End of the schema for adding the android specific tags in AndroidManifest.xml file --> + +</application> http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/2454c94f/MD5Checker/src/MD5Checker.mxml ---------------------------------------------------------------------- diff --git a/MD5Checker/src/MD5Checker.mxml b/MD5Checker/src/MD5Checker.mxml new file mode 100644 index 0000000..9171cb9 --- /dev/null +++ b/MD5Checker/src/MD5Checker.mxml @@ -0,0 +1,414 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +--> +<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" + xmlns:s="library://ns.adobe.com/flex/spark" + xmlns:mx="library://ns.adobe.com/flex/mx" + preinitialize="getInvoke()" + applicationComplete="setup()"> + <fx:Declarations> + <!-- Place non-visual elements (e.g., services, value objects) here --> + </fx:Declarations> + <fx:Script> + <![CDATA[ + import org.apache.flex.crypto.MD5Stream; + + private static var DEFAULT_READBUFFER_SIZE:int = 2 * 1024 * 1024; + private static var GCL:String = "Google Closure Library"; + + private var data:Array = []; + + private function getInvoke():void { + var nativeApplication:NativeApplication = NativeApplication.nativeApplication; + nativeApplication.addEventListener(InvokeEvent.INVOKE, parseArgs); + } + private var logFileName:String = "MD5CheckerLog.txt"; + + private function parseArgs(event:InvokeEvent):void { + for each (var s:String in event.arguments) { + if (s.indexOf("-log=") == 0) { + logFileName = s.substring(5); + } + } + } + + // last modified dates and checksum map by url; + private var configURL:String = "http://flex.apache.org/installer/sdk-installer-config-4.0.xml"; + private var fs:FileStream = new FileStream(); + private var f:File; + + private function setup():void + { + f = File.documentsDirectory.resolvePath(logFileName); + fs.open(f, FileMode.WRITE); + + var urlRequest:URLRequest = new URLRequest(configURL); + urlRequest.followRedirects = true; + urlRequest.cacheResponse = false; + urlRequest.method = URLRequestMethod.GET; + xmlLoader.dataFormat = URLLoaderDataFormat.TEXT; + xmlLoader.addEventListener(Event.COMPLETE, xmlcompleteHandler); + xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, xmlerrorHandler); + xmlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, xmlerrorHandler); + xmlLoader.load(urlRequest); + progressLabel.text = "Fetching sdk-installer-config-4.0.xml"; + } + + private var xml:XML; + + private function xmlcompleteHandler(event:Event):void + { + xml = new XML(xmlLoader.data as String); + var xmlList:XMLList; + + var item:Object; + + xmlList = xml["google-closure-library"]; + for each (var node:XML in xmlList) + { + item = {}; + item.label = GCL; + item.url = node.@server.toString() + "/" + node.@folder.toString() + "/" + node.@file.toString(); + item.md5 = node.@md5.toString(); + if (!item.md5) + continue; + item.cacheID = node.@cacheID.toString(); + item.node = node; + data.push(item); + } + + xmlList = xml.flashsdk.versions.children(); + for each (node in xmlList) + { + item = {}; + item.label = "Flash PlayerGlobal " + node.@displayVersion.toString(); + item.url = node.path.toString() + node.file.toString(); + item.md5 = node.md5.toString(); + if (!item.md5) + continue; + item.cacheID = node.@cacheID.toString(); + item.node = node; + data.push(item); + } + + /* + xmlList = xml.airsdk.windows.versions.children(); + for each (node in xmlList) + { + item = {}; + item.label = "AIR Windows " + node.@displayVersion.toString(); + item.url = node.path.toString() + node.file.toString(); + item.md5 = node.md5.toString(); + if (!item.md5) + continue; + item.cacheID = node.@cacheID.toString(); + item.node = node; + data.push(item); + } + + xmlList = xml.airsdk.mac.versions.children(); + for each (node in xmlList) + { + item = {}; + item.label = "AIR Mac " + node.@displayVersion.toString(); + item.url = node.path.toString() + node.file.toString(); + item.md5 = node.md5.toString(); + if (!item.md5) + continue; + item.cacheID = node.@cacheID.toString(); + item.node = node; + data.push(item); + } + */ + dg.dataProvider = new ArrayList(data); + checkSums(); + } + + private function xmlerrorHandler(event:Event):void + { + event.preventDefault(); + fs.writeUTFBytes("Unable to fetch " + configURL); + fs.close(); + this.nativeApplication.exit(-1); + } + + + private var xmlLoader:URLLoader = new URLLoader(); + + private var current:int; + private var lastModified:String; + + private function checkSums():void + { + current = 0; + checkCurrent(); + } + + private var urlHeadLoader:URLLoader = new URLLoader(); + private var urlLoader:URLLoader = new URLLoader(); + private var urlLoader2:URLLoader = new URLLoader(); + + private var nodeChanged:Boolean; + + private function checkCurrent():void + { + if (current >= data.length) + { + fs.close(); + this.nativeApplication.exit(nodeChanged ? -1 : 0); + return; + } + + lastModified = null; + + var urlRequest:URLRequest = new URLRequest(data[current].url); + urlRequest.followRedirects = true; + urlRequest.cacheResponse = false; + urlRequest.method = URLRequestMethod.HEAD; + urlHeadLoader.dataFormat = URLLoaderDataFormat.BINARY; + urlHeadLoader.addEventListener(Event.COMPLETE, headcompleteHandler); + urlHeadLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS,headstatusHandler); + urlHeadLoader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler); + urlHeadLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler); + urlHeadLoader.load(urlRequest); + progressLabel.text = "Checking " + data[current].url; + } + + private var lastStatus:int; + + private function headstatusHandler(event:HTTPStatusEvent):void + { + lastStatus = event.status; + if (event.status >= 400) + { + // some problem. skip, go to next one + current++; + checkCurrent(); + } + else + { + var foundLastModified:Boolean = false; + var headers:Array = event.responseHeaders; + for each (var header:URLRequestHeader in headers) + { + if (header.name == "Last-Modified") + { + lastModified = header.value; + foundLastModified = true; + } + else if (header.name == "Etag" && lastModified == null) + { + lastModified = header.value; + foundLastModified = true; + } + } + if (!foundLastModified) + { + trace("no last modified or etag header"); + } + } + } + + private function headcompleteHandler(event:Event):void + { + if (data[current].cacheID != lastModified) + { + download(); + } + else + { + current++; + checkCurrent(); + } + } + + private function download():void + { + var urlRequest:URLRequest = new URLRequest(data[current].url); + urlRequest.followRedirects = true; + urlRequest.cacheResponse = false; + urlRequest.method = URLRequestMethod.GET; + urlLoader.dataFormat = URLLoaderDataFormat.BINARY; + urlLoader.addEventListener(Event.COMPLETE, completeHandler); + urlHeadLoader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, statusHandler); + urlLoader.addEventListener(ProgressEvent.PROGRESS, progressHandler); + urlLoader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler); + urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler); + urlLoader.load(urlRequest); + progressLabel.text = "Downloading " + data[current].url; + } + + private function progressHandler(event:ProgressEvent):void + { + pb.setProgress(event.bytesLoaded, event.bytesTotal); + pbCurrent.text = event.bytesLoaded.toString(); + pbTotal.text = event.bytesTotal.toString(); + } + + private function statusHandler(event:HTTPStatusEvent):void + { + lastStatus = event.status; + } + + private function errorHandler(event:Event):void + { + event.preventDefault(); + current++; + checkCurrent(); + } + + + private var md5:MD5Stream; + private var ba:ByteArray; + + private function completeHandler(event:Event):void + { + if (lastStatus < 300) + { + md5 = new MD5Stream(); + md5.resetFields(); + ba = urlLoader.data as ByteArray; + progressLabel.text = "Computing checksum for " + data[current].url; + getSum(); + } + else + { + current++; + checkCurrent(); + } + } + + private function getSum():void + { + if (ba.bytesAvailable < DEFAULT_READBUFFER_SIZE) + { + sumComplete(); + return; + } + md5.update(ba, DEFAULT_READBUFFER_SIZE); + pb.setProgress(ba.position, ba.length); + pbCurrent.text = ba.position.toString(); + pbTotal.text = ba.length.toString(); + callLater(getSum); + } + + private var sum:String; + + private function sumComplete():void + { + sum = md5.complete(ba, ba.length); + retries = 1; + redownload(); + } + + private function redownload():void + { + var urlRequest:URLRequest = new URLRequest(data[current].url); + urlRequest.followRedirects = true; + urlRequest.cacheResponse = false; + urlRequest.method = URLRequestMethod.GET; + urlLoader2.dataFormat = URLLoaderDataFormat.BINARY; + urlLoader2.addEventListener(Event.COMPLETE, recompleteHandler); + urlLoader2.addEventListener(ProgressEvent.PROGRESS, progressHandler); + urlLoader2.addEventListener(IOErrorEvent.IO_ERROR, reerrorHandler); + urlLoader2.addEventListener(SecurityErrorEvent.SECURITY_ERROR, reerrorHandler); + urlLoader2.load(urlRequest); + progressLabel.text = "Verifying CheckSum (" + retries.toString() + ")"; + } + + private var retries:int; + + private function reerrorHandler(event:Event):void + { + if (retries < 4) + redownload(); + } + + private function recompleteHandler(event:Event):void + { + md5 = new MD5Stream(); + md5.resetFields(); + ba = urlLoader2.data as ByteArray; + getSum2(); + } + + private function getSum2():void + { + if (ba.bytesAvailable < DEFAULT_READBUFFER_SIZE) + { + sumComplete2(); + return; + } + md5.update(ba, DEFAULT_READBUFFER_SIZE); + pb.setProgress(ba.position, ba.length); + pbCurrent.text = ba.position.toString(); + pbTotal.text = ba.length.toString(); + callLater(getSum2); + } + + private function sumComplete2():void + { + var sum2:String = md5.complete(ba, ba.length); + if (sum == sum2) + { + data[current].cacheID = lastModified; + data[current].md5 = sum; + fs.writeUTFBytes("Old Node:\n"); + fs.writeUTFBytes(data[current].node.toXMLString() + "\n"); + fs.writeUTFBytes("New Node:\n"); + data[current].node.@cacheID = lastModified; + if (data[current].label == GCL) + data[current].node.@md5 = sum; + else + data[current].node.md5 = sum; + nodeChanged = true; + fs.writeUTFBytes(data[current].node.toXMLString() + "\n"); + dg.dataProvider.itemUpdated(data[current]); + current++; + checkCurrent(); + } + else + { + sum = sum2; + redownload(); + } + } + + ]]> + </fx:Script> + <s:VGroup width="100%"> + <s:DataGrid id="dg" width="100%" height="300"> + <s:columns> + <s:ArrayList> + <s:GridColumn dataField="label" /> + <s:GridColumn dataField="url" /> + <s:GridColumn dataField="md5" /> + <s:GridColumn dataField="cacheID" /> + </s:ArrayList> + </s:columns> + </s:DataGrid> + <s:Label id="progressLabel" width="100%" /> + <mx:ProgressBar id="pb" width="100%" mode="manual" /> + <s:HGroup> + <s:Label id="pbCurrent" /> + <s:Label text="out of" /> + <s:Label id="pbTotal" /> + </s:HGroup> + </s:VGroup> +</s:WindowedApplication>