flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aha...@apache.org
Subject [03/48] git commit: [flex-utilities] [refs/heads/develop] - move ant_on_air into flex-installer
Date Mon, 15 Jun 2015 06:30:37 GMT
http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/f954e6f6/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/FileUtils.as
----------------------------------------------------------------------
diff --git a/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/FileUtils.as b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/FileUtils.as
new file mode 100644
index 0000000..ea3166b
--- /dev/null
+++ b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/FileUtils.as
@@ -0,0 +1,657 @@
+/*
+*  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.
+*
+*/
+package org.apache.flex.ant.tags.filesetClasses
+{
+    import flash.filesystem.File;
+    import flash.system.Capabilities;
+    
+    import org.apache.flex.ant.Ant;
+    import org.apache.flex.ant.tags.filesetClasses.exceptions.BuildException;
+    import org.apache.flex.ant.tags.filesetClasses.exceptions.IOException;
+    
+    /**
+     * Ported from org.apache.tools.ant.util on 12/3/13.  File copying
+     * was removed.  So was tempfile, newfile, readfully and contentEquals.
+     * 
+     * This class also encapsulates methods which allow Files to be
+     * referred to using abstract path names which are translated to native
+     * system file paths at runtime as well as copying files or setting
+     * their last modification time.
+     *
+     */
+    public class FileUtils {
+        private static const PRIMARY_INSTANCE:FileUtils = new FileUtils();
+                
+        private static const ON_WINDOWS:Boolean = Capabilities.os.indexOf("Win") != -1;
+        private static const ON_DOS:Boolean = Capabilities.os.indexOf("Win") != -1;
+                
+        /**
+         * The granularity of timestamps under Unix.
+         */
+        public static const UNIX_FILE_TIMESTAMP_GRANULARITY:int = 1000;
+        
+        /**
+         * The granularity of timestamps under the NT File System.
+         * NTFS has a granularity of 100 nanoseconds, which is less
+         * than 1 millisecond, so we round this up to 1 millisecond.
+         */
+        public static const NTFS_FILE_TIMESTAMP_GRANULARITY:int = 1;
+                
+        /**
+         * Method to retrieve The FileUtils, which is shared by all users of this
+         * method.
+         * @return an instance of FileUtils.
+         * @since Ant 1.6.3
+         */
+        public static function getFileUtils():FileUtils {
+            return PRIMARY_INSTANCE;
+        }
+        
+        /**
+         * Empty constructor.
+         */
+        public function FileUtils() {
+        }
+        
+        /**
+         * Get the URL for a file taking into account # characters.
+         *
+         * @param file the file whose URL representation is required.
+         * @return The FileURL value.
+         * @throws MalformedURLException if the URL representation cannot be
+         *      formed.
+        public URL getFileURL(File file) throws MalformedURLException {
+            return new URL(file.toURI().toASCIIString());
+        }
+         */
+                
+        /**
+         * Calls File.setLastModified(long time). Originally written to
+         * to dynamically bind to that call on Java1.2+.
+         *
+         * @param file the file whose modified time is to be set
+         * @param time the time to which the last modified time is to be set.
+         *             if this is -1, the current time is used.
+         */
+        public function setFileLastModified(file:File, time:Number):void {
+            throw new Error("not supported in AIR");
+        }
+        
+        /**
+         * Interpret the filename as a file relative to the given file
+         * unless the filename already represents an absolute filename.
+         * Differs from <code>new File(file, filename)</code> in that
+         * the resulting File's path will always be a normalized,
+         * absolute pathname.  Also, if it is determined that
+         * <code>filename</code> is context-relative, <code>file</code>
+         * will be discarded and the reference will be resolved using
+         * available context/state information about the filesystem.
+         *
+         * @param file the "reference" file for relative paths. This
+         * instance must be an absolute file and must not contain
+         * &quot;./&quot; or &quot;../&quot; sequences (same for \ instead
+         * of /).  If it is null, this call is equivalent to
+         * <code>new java.io.File(filename).getAbsoluteFile()</code>.
+         *
+         * @param filename a file name.
+         *
+         * @return an absolute file.
+         * @throws java.lang.NullPointerException if filename is null.
+         */
+        public function resolveFile(file:File, filename:String):File {
+            if (!isAbsolutePath(filename)) {
+                var sep:String = File.separator;
+                filename = filename.replace(/\//g, sep).replace(/\\/g, sep);
+                if (isContextRelativePath(filename)) {
+                    file = null;
+                    // on cygwin, our current directory can be a UNC;
+                    // assume user.dir is absolute or all hell breaks loose...
+                    var udir:String = File.userDirectory.nativePath;
+                    if (filename.charAt(0) == sep && udir.charAt(0) == sep) {
+                        filename = dissect(udir)[0] + filename.substring(1);
+                    }
+                }
+                filename = new File(file.nativePath + File.separator + filename).nativePath;
+            }
+            return normalize(filename);
+        }
+        
+        /**
+         * On DOS and NetWare, the evaluation of certain file
+         * specifications is context-dependent.  These are filenames
+         * beginning with a single separator (relative to current root directory)
+         * and filenames with a drive specification and no intervening separator
+         * (relative to current directory of the specified root).
+         * @param filename the filename to evaluate.
+         * @return true if the filename is relative to system context.
+         * @throws java.lang.NullPointerException if filename is null.
+         * @since Ant 1.7
+         */
+        public static function isContextRelativePath(filename:String):Boolean {
+            if (!ON_DOS || filename.length == 0) {
+                return false;
+            }
+            var sep:String = File.separator;
+            filename = filename.replace(/\//g, sep).replace(/\\/g, sep);
+            var c:String = filename.charAt(0);
+            var len:int = filename.length;
+            return (c == sep && (len == 1 || filename.charAt(1) != sep))
+            || (Character.isLetter(c) && len > 1
+                && filename.indexOf(':') == 1
+                && (len == 2 || filename.charAt(2) != sep));
+        }
+        
+                
+        /**
+         * Verifies that the specified filename represents an absolute path.
+         * Differs from new java.io.File("filename").isAbsolute() in that a path
+         * beginning with a double file separator--signifying a Windows UNC--must
+         * at minimum match "\\a\b" to be considered an absolute path.
+         * @param filename the filename to be checked.
+         * @return true if the filename represents an absolute path.
+         * @throws java.lang.NullPointerException if filename is null.
+         * @since Ant 1.6.3
+         */
+        public static function isAbsolutePath(filename:String):Boolean {
+            var len:int = filename.length;
+            if (len == 0) {
+                return false;
+            }
+            var sep:String = File.separator;
+            filename = filename.replace(/\//g, sep).replace(/\\/g, sep);
+            var c:String = filename.charAt(0);
+            if (!ON_DOS)
+                return (c == sep);
+            
+            if (c == sep) {
+                // CheckStyle:MagicNumber OFF
+                if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) {
+                    return false;
+                }
+                // CheckStyle:MagicNumber ON
+                var nextsep:int = filename.indexOf(sep, 2);
+                return nextsep > 2 && nextsep + 1 < len;
+            }
+            var colon:int = filename.indexOf(':');
+            return (Character.isLetter(c) && colon == 1
+                && filename.length > 2 && filename.charAt(2) == sep);
+        }
+        
+        /**
+         * Translate a path into its native (platform specific) format.
+         * <p>
+         * This method uses PathTokenizer to separate the input path
+         * into its components. This handles DOS style paths in a relatively
+         * sensible way. The file separators are then converted to their platform
+         * specific versions.
+         *
+         * @param toProcess The path to be translated.
+         *                  May be <code>null</code>.
+         *
+         * @return the native version of the specified path or
+         *         an empty string if the path is <code>null</code> or empty.
+         *
+         * @since ant 1.7
+         * @see PathTokenizer
+         */
+        public static function translatePath(toProcess:String):String {
+            if (toProcess == null || toProcess.length == 0) {
+                return "";
+            }
+            var path:String = "";
+            var tokenizer:PathTokenizer = new PathTokenizer(toProcess);
+            while (tokenizer.hasMoreTokens()) {
+                var pathComponent:String = tokenizer.nextToken();
+                pathComponent = pathComponent.replace(/\//g, File.separator);
+                pathComponent = pathComponent.replace(/\\/g, File.separator);
+                if (path.length != 0) {
+                    path += File.separator;
+                }
+                path += pathComponent;
+            }
+            return path;
+        }
+        
+        /**
+         * &quot;Normalize&quot; the given absolute path.
+         *
+         * <p>This includes:
+         * <ul>
+         *   <li>Uppercase the drive letter if there is one.</li>
+         *   <li>Remove redundant slashes after the drive spec.</li>
+         *   <li>Resolve all ./, .\, ../ and ..\ sequences.</li>
+         *   <li>DOS style paths that start with a drive letter will have
+         *     \ as the separator.</li>
+         * </ul>
+         * Unlike {@link File#getCanonicalPath()} this method
+         * specifically does not resolve symbolic links.
+         *
+         * @param path the path to be normalized.
+         * @return the normalized version of the path.
+         *
+         * @throws java.lang.NullPointerException if path is null.
+         */
+        public function normalize(path:String):File {
+            var s:Array = new Array();
+            var dissect:Vector.<String> = dissect(path);
+            s.push(dissect[0]);
+            
+            var tok:StringTokenizer = new StringTokenizer(dissect[1], File.separator);
+            while (tok.hasMoreTokens()) {
+                var thisToken:String = tok.nextToken();
+                if ("." == thisToken) {
+                    continue;
+                }
+                if (".." == thisToken) {
+                    if (s.length < 2) {
+                        // Cannot resolve it, so skip it.
+                        return new File(path);
+                    }
+                    s.pop();
+                } else { // plain component
+                    s.push(thisToken);
+                }
+            }
+            var sb:String = "";
+            var size:int = s.length;
+            for (var i:int = 0; i < size; i++) {
+                if (i > 1) {
+                    // not before the filesystem root and not after it, since root
+                    // already contains one
+                    sb += File.separator;
+                }
+                sb += s[i];
+            }
+            return new File(sb);
+        }
+        
+        /**
+         * Dissect the specified absolute path.
+         * @param path the path to dissect.
+         * @return String[] {root, remaining path}.
+         * @throws java.lang.NullPointerException if path is null.
+         * @since Ant 1.7
+         */
+        public function dissect(path:String):Vector.<String> {
+            var sep:String = File.separator;
+            path = path.replace(/\//g, sep).replace(/\\/g, sep);
+            
+            // make sure we are dealing with an absolute path
+            if (!isAbsolutePath(path)) {
+                throw new BuildException(path + " is not an absolute path");
+            }
+            var root:String = null;
+            var colon:int = path.indexOf(':');
+            if (colon > 0 && ON_DOS) {
+                
+                var next:int = colon + 1;
+                root = path.substring(0, next);
+                var ca:Vector.<String> = Vector.<String>(path.split(""));
+                root += sep;
+                //remove the initial separator; the root has it.
+                next = (ca[next] == sep) ? next + 1 : next;
+                
+                var sbPath:String = "";
+                // Eliminate consecutive slashes after the drive spec:
+                for (var i:int = next; i < ca.length; i++) {
+                    if (ca[i] != sep || ca[i - 1] != sep) {
+                        sbPath += ca[i];
+                    }
+                }
+                path = sbPath;
+            } else if (path.length > 1 && path.charAt(1) == sep) {
+                // UNC drive
+                var nextsep:int = path.indexOf(sep, 2);
+                nextsep = path.indexOf(sep, nextsep + 1);
+                root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path;
+                path = path.substring(root.length);
+            } else {
+                root = File.separator;
+                path = path.substring(1);
+            }
+            return Vector.<String>([root, path]);
+        }
+        
+       
+        /**
+         * This was originally an emulation of {@link File#getParentFile} for JDK 1.1, but it is now
+         * implemented using that method (Ant 1.6.3 onwards).
+         *
+         * @param f the file whose parent is required.
+         * @return the given file's parent, or null if the file does not have a parent.
+         * @since 1.10
+         * @deprecated since 1.7. Just use {@link File#getParentFile} directly.
+         */
+        public function getParentFile(f:File):File {
+            return (f == null) ? null : f.parent;
+        }
+        
+        /**
+         * Checks whether a given file is a symbolic link.
+         *
+         * <p>It doesn't really test for symbolic links but whether the
+         * canonical and absolute paths of the file are identical--this
+         * may lead to false positives on some platforms.</p>
+         *
+         * @param parent the parent directory of the file to test
+         * @param name the name of the file to test.
+         *
+         * @return true if the file is a symbolic link.
+         * @throws IOException on error.
+         * @since Ant 1.5
+         * @deprecated use SymbolicLinkUtils instead
+         */
+        public function isSymbolicLink(parent:File, name:String):Boolean
+        {
+            if (parent == null) {
+                return new File(name).isSymbolicLink;
+            }
+            return new File(parent.nativePath + File.separator + name).isSymbolicLink;
+        }
+        
+        /**
+         * Removes a leading path from a second path.
+         *
+         * @param leading The leading path, must not be null, must be absolute.
+         * @param path The path to remove from, must not be null, must be absolute.
+         *
+         * @return path's normalized absolute if it doesn't start with
+         * leading; path's path with leading's path removed otherwise.
+         *
+         * @since Ant 1.5
+         */
+        public function removeLeadingPath(leading:File, path:File):String {
+            var l:String = normalize(leading.nativePath).nativePath;
+            var p:String = normalize(path.nativePath).nativePath;
+            if (l == p) {
+                return "";
+            }
+            // ensure that l ends with a /
+            // so we never think /foo was a parent directory of /foobar
+            if (l.charAt(l.length - 1) != File.separator) {
+                l += File.separator;
+            }
+            return (p.indexOf(l) == 0) ? p.substring(l.length) : p;
+        }
+        
+        /**
+         * Learn whether one path "leads" another.
+         * @param leading The leading path, must not be null, must be absolute.
+         * @param path The path to remove from, must not be null, must be absolute.
+         * @return true if path starts with leading; false otherwise.
+         * @since Ant 1.7
+         */
+        public function isLeadingPath(leading:File, path:File):Boolean {
+            var l:String = normalize(leading.nativePath).nativePath;
+            var p:String = normalize(path.nativePath).nativePath;
+            if (l == p) {
+                return true;
+            }
+            // ensure that l ends with a /
+            // so we never think /foo was a parent directory of /foobar
+            if (l.charAt(l.length - 1) != File.separator) {
+                l += File.separator;
+            }
+            return p.indexOf(l) == 0;
+        }
+        
+        /**
+         * Compares two filenames.
+         *
+         * <p>Unlike java.io.File#equals this method will try to compare
+         * the absolute paths and &quot;normalize&quot; the filenames
+         * before comparing them.</p>
+         *
+         * @param f1 the file whose name is to be compared.
+         * @param f2 the other file whose name is to be compared.
+         *
+         * @return true if the file are for the same file.
+         *
+         * @since Ant 1.5.3
+         */
+        public function fileNameEquals(f1:File, f2:File):Boolean {
+            return normalize(f1.nativePath).nativePath ==
+                normalize(f2.nativePath).nativePath;
+        }
+        
+        /**
+         * Are the two File instances pointing to the same object on the
+         * file system?
+         * @since Ant 1.8.2
+         */
+        public function areSame(f1:File, f2:File):Boolean {
+            if (f1 == null && f2 == null) {
+                return true;
+            }
+            if (f1 == null || f2 == null) {
+                return false;
+            }
+            var f1Normalized:File = normalize(f1.nativePath);
+            var f2Normalized:File = normalize(f2.nativePath);
+            if (f1Normalized.nativePath == f2Normalized.nativePath)
+                return true;
+            f1Normalized.canonicalize();
+            f2Normalized.canonicalize();
+            return f1Normalized.nativePath == f2Normalized.nativePath;
+        }
+        
+        /**
+         * Renames a file, even if that involves crossing file system boundaries.
+         *
+         * <p>This will remove <code>to</code> (if it exists), ensure that
+         * <code>to</code>'s parent directory exists and move
+         * <code>from</code>, which involves deleting <code>from</code> as
+         * well.</p>
+         *
+         * @param from the file to move.
+         * @param to the new file name.
+         *
+         * @throws IOException if anything bad happens during this
+         * process.  Note that <code>to</code> may have been deleted
+         * already when this happens.
+         *
+         * @since Ant 1.6
+         */
+        public function rename(from:File, to:File):void {
+            // identical logic lives in Move.renameFile():
+            from.canonicalize()
+            from = normalize(from.nativePath);
+            to = normalize(to.nativePath);
+            if (!from.exists) {
+                Ant.currentAnt.output("Cannot rename nonexistent file " + from);
+                return;
+            }
+            if (from.nativePath == to.nativePath) {
+                Ant.currentAnt.output("Rename of " + from + " to " + to + " is a no-op.");
+                return;
+            }
+            if (to.exists)
+                to.deleteFile();
+            if (to.exists && !(areSame(from, to))) {
+                throw new IOException("Failed to delete " + to + " while trying to rename " + from);
+            }
+            var parent:File = to.parent;
+            if (parent != null && !parent.exists && !parent.createDirectory()) {
+                throw new IOException("Failed to create directory " + parent
+                    + " while trying to rename " + from);
+            }
+            if (!from.moveTo(to)) {
+                from.copyTo(to);
+                from.deleteFile();
+                if (from.exists) {
+                    throw new IOException("Failed to delete " + from + " while trying to rename it.");
+                }
+            }
+        }
+        
+        /**
+         * Get the granularity of file timestamps. The choice is made based on OS, which is
+         * incorrect--it should really be by filesystem. We do not have an easy way to probe for file
+         * systems, however, so this heuristic gives us a decent default.
+         *
+         * @return the difference, in milliseconds, which two file timestamps must have in order for the
+         *         two files to be considered to have different timestamps.
+         */
+        public function getFileTimestampGranularity():Number {
+            if (ON_WINDOWS) {
+                return NTFS_FILE_TIMESTAMP_GRANULARITY;
+            }
+            return UNIX_FILE_TIMESTAMP_GRANULARITY;
+        }
+        
+        
+        /**
+         * Returns true if the source is older than the dest.
+         * If the dest file does not exist, then the test returns false; it is
+         * implicitly not up do date.
+         * @param source source file (should be the older).
+         * @param dest dest file (should be the newer).
+         * @param granularity an offset added to the source time.
+         * @return true if the source is older than the dest after accounting
+         *              for granularity.
+         * @since Ant 1.6.3
+         */
+        public function isUpToDate(source:File, dest:File, granularity:Object = null):Boolean {
+            if (granularity == null)
+                granularity = getFileTimestampGranularity();
+            //do a check for the destination file existing
+            if (!dest.exists) {
+                //if it does not, then the file is not up to date.
+                return false;
+            }
+            var sourceTime:Date = source.modificationDate;
+            var destTime:Date = dest.modificationDate;
+            return isUpToDateDate(sourceTime.time, destTime.time, granularity as Number);
+        }
+        
+        /**
+         * Compare two timestamps for being up to date using
+         * the specified granularity.
+         *
+         * @param sourceTime timestamp of source file.
+         * @param destTime timestamp of dest file.
+         * @param granularity os/filesys granularity.
+         * @return true if the dest file is considered up to date.
+         */
+        public function isUpToDateDate(sourceTime:Number, destTime:Number, granularity:Number = NaN):Boolean {
+            if (isNaN(granularity))
+                granularity = getFileTimestampGranularity();
+            return destTime != -1 && destTime >= sourceTime + granularity;
+        }
+                
+        
+        /**
+         * Calculates the relative path between two files.
+         * <p>
+         * Implementation note:<br/> This function may throw an IOException if an I/O error occurs
+         * because its use of the canonical pathname may require filesystem queries.
+         * </p>
+         *
+         * @param fromFile the <code>File</code> to calculate the path from
+         * @param toFile the <code>File</code> to calculate the path to
+         * @return the relative path between the files
+         * @throws Exception for undocumented reasons
+         * @see File#getCanonicalPath()
+         *
+         * @since Ant 1.7
+         */
+        public static function getRelativePath(fromFile:File, toFile:File):String {
+            fromFile.canonicalize();
+            toFile.canonicalize();
+            var fromPath:String = fromFile.nativePath;
+            var toPath:String = toFile.nativePath;
+            
+            // build the path stack info to compare
+            var fromPathStack:Vector.<String> = getPathStack(fromPath);
+            var toPathStack:Vector.<String> = getPathStack(toPath);
+            
+            if (0 < toPathStack.length && 0 < fromPathStack.length) {
+                if (!fromPathStack[0] == toPathStack[0]) {
+                    // not the same device (would be "" on Linux/Unix)
+                    
+                    return getPath(toPathStack);
+                }
+            } else {
+                // no comparison possible
+                return getPath(toPathStack);
+            }
+            
+            var minLength:int = Math.min(fromPathStack.length, toPathStack.length);
+            var same:int = 1; // Used outside the for loop
+            
+            // get index of parts which are equal
+            for (;
+                same < minLength && fromPathStack[same] == toPathStack[same];
+                same++) {
+                // Do nothing
+            }
+            
+            var relativePathStack:Vector.<String> = new Vector.<String>();
+            
+            // if "from" part is longer, fill it up with ".."
+            // to reach path which is equal to both paths
+            for (var i:int = same; i < fromPathStack.length; i++) {
+                relativePathStack.push("..");
+            }
+            
+            // fill it up path with parts which were not equal
+            for (i = same; i < toPathStack.length; i++) {
+                relativePathStack.push(toPathStack[i]);
+            }
+            
+            return getPath(relativePathStack);
+        }
+        
+        /**
+         * Gets all names of the path as an array of <code>String</code>s.
+         *
+         * @param path to get names from
+         * @return <code>String</code>s, never <code>null</code>
+         *
+         * @since Ant 1.7
+         */
+        public static function getPathStack(path:String):Vector.<String> {
+            var normalizedPath:String = path.replace(new RegExp(File.separator, "g"), '/');
+            
+            return Vector.<String>(normalizedPath.split("/"));
+        }
+        
+        /**
+         * Gets path from a <code>List</code> of <code>String</code>s.
+         *
+         * @param pathStack <code>List</code> of <code>String</code>s to be concated as a path.
+         * @param separatorChar <code>char</code> to be used as separator between names in path
+         * @return <code>String</code>, never <code>null</code>
+         *
+         * @since Ant 1.7
+         */
+        public static function getPath(pathStack:Vector.<String>, separatorChar:String = "/"):String {
+            var buffer:String = ""
+            
+            if (pathStack.length) {
+                buffer += pathStack.shift();
+            }
+            while (pathStack.length) {
+                buffer += separatorChar;
+                buffer += pathStack.shift();
+            }
+            return buffer;
+        }
+        
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/f954e6f6/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/PathTokenizer.as
----------------------------------------------------------------------
diff --git a/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/PathTokenizer.as b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/PathTokenizer.as
new file mode 100644
index 0000000..3e04911
--- /dev/null
+++ b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/PathTokenizer.as
@@ -0,0 +1,118 @@
+/*
+*  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.
+*
+*/
+
+package org.apache.flex.ant.tags.filesetClasses
+{        
+    import flash.system.Capabilities;
+    
+    import mx.utils.StringUtil;
+    
+        /**
+         * Ported from org.apache.tools.ant.PathTokenizer.java on 12/3/13. 
+         * A Path tokenizer takes a path and returns the components that make up
+         * that path.
+         *
+         * The path can use path separators of either ':' or ';' and file separators
+         * of either '/' or '\'.
+         *
+         */
+        public class PathTokenizer {
+            /**
+             * A tokenizer to break the string up based on the ':' or ';' separators.
+             */
+            private var tokenizer:StringTokenizer;
+            
+            /**
+             * A String which stores any path components which have been read ahead
+             * due to DOS filesystem compensation.
+             */
+            private var lookahead:String = null;
+            
+            /**
+             * Flag to indicate whether or not we are running on a platform with a
+             * DOS style filesystem
+             */
+            private var dosStyleFilesystem:Boolean;
+            
+            /**
+             * Constructs a path tokenizer for the specified path.
+             *
+             * @param path The path to tokenize. Must not be <code>null</code>.
+             */
+            public function PathTokenizer(path:String) {
+                // on Windows and Unix, we can ignore delimiters and still have
+                // enough information to tokenize correctly.
+                tokenizer = new StringTokenizer(path, ":;", false);
+                dosStyleFilesystem = Capabilities.os.indexOf("Win") != -1;
+            }
+            
+            /**
+             * Tests if there are more path elements available from this tokenizer's
+             * path. If this method returns <code>true</code>, then a subsequent call
+             * to nextToken will successfully return a token.
+             *
+             * @return <code>true</code> if and only if there is at least one token
+             * in the string after the current position; <code>false</code> otherwise.
+             */
+            public function hasMoreTokens():Boolean {
+                if (lookahead != null) {
+                    return true;
+                }
+                
+                return tokenizer.hasMoreTokens();
+            }
+            
+            /**
+             * Returns the next path element from this tokenizer.
+             *
+             * @return the next path element from this tokenizer.
+             *
+             * @exception NoSuchElementException if there are no more elements in this
+             *            tokenizer's path.
+             */
+            public function nextToken():String {
+                var token:String = null;
+                if (lookahead != null) {
+                    token = lookahead;
+                    lookahead = null;
+                } else {
+                    token = StringUtil.trim(tokenizer.nextToken());
+                }
+                
+                if (token.length == 1 && Character.isLetter(token.charAt(0))
+                    && dosStyleFilesystem
+                    && tokenizer.hasMoreTokens()) {
+                    // we are on a dos style system so this path could be a drive
+                    // spec. We look at the next token
+                    var nextToken:String = StringUtil.trim(tokenizer.nextToken());
+                    if (nextToken.indexOf("\\") == 0 || nextToken.indexOf("/") == 0) {
+                        // we know we are on a DOS style platform and the next path
+                        // starts with a slash or backslash, so we know this is a
+                        // drive spec
+                        token += ":" + nextToken;
+                    } else {
+                        // store the token just read for next time
+                        lookahead = nextToken;
+                    }
+                }
+                return token;
+            }
+        }
+        
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/f954e6f6/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/Reference.as
----------------------------------------------------------------------
diff --git a/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/Reference.as b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/Reference.as
new file mode 100644
index 0000000..1e9ce09
--- /dev/null
+++ b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/Reference.as
@@ -0,0 +1,106 @@
+/*
+*  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.
+*
+*/
+package org.apache.flex.ant.tags.filesetClasses
+{
+    import org.apache.flex.ant.tags.Project;
+    import org.apache.flex.ant.tags.filesetClasses.exceptions.BuildException;
+
+    /**
+     * Ported from org.apache.tools.ant.types.Reference.java on 12/3/13. 
+     * Class to hold a reference to another object in the project.
+     *
+     */
+    public class Reference {
+    
+        private var refid:String;
+        private var project:Project;
+    
+        /**
+         * Create a reference to a named ID in a particular project.
+         * @param p the project this reference is associated with
+         * @param id the name of this reference
+         * @since Ant 1.6.3
+         */
+        public function Reference(p:Project, id:String) {
+            setRefId(id);
+            setProject(p);
+        }
+    
+        /**
+         * Set the reference id. Should not normally be necessary;
+         * use {@link Reference#Reference(Project, String)}.
+         * @param id the reference id to use
+         */
+        public function setRefId(id:String):void {
+            refid = id;
+        }
+    
+        /**
+         * Get the reference id of this reference.
+         * @return the reference id
+         */
+        public function getRefId():String {
+            return refid;
+        }
+    
+        /**
+         * Set the associated project. Should not normally be necessary;
+         * use {@link Reference#Reference(Project,String)}.
+         * @param p the project to use
+         * @since Ant 1.6.3
+         */
+        public function setProject(p:Project):void {
+            this.project = p;
+        }
+    
+        /**
+         * Get the associated project, if any; may be null.
+         * @return the associated project
+         * @since Ant 1.6.3
+         */
+        public function getProject():Project {
+            return project;
+        }
+    
+        /**
+         * Resolve the reference, using the associated project if
+         * it set, otherwise use the passed in project.
+         * @param fallback the fallback project to use if the project attribute of
+         *                 reference is not set.
+         * @return the dereferenced object.
+         * @throws BuildException if the reference cannot be dereferenced.
+         */
+        public function getReferencedObject(fallback:Project = null):Object {
+            if (refid == null) {
+                throw new BuildException("No reference specified");
+            }
+            if (fallback == null)
+            {
+                if (project == null) {
+                    throw new BuildException("No project set on reference to " + refid);
+                }
+            }    
+            
+            var o:Object = project == null ? fallback.getReference(refid) : project.getReference(refid);
+            if (o == null) {
+                throw new BuildException("Reference " + refid + " not found.");
+            }
+            return o;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/f954e6f6/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/Resource.as
----------------------------------------------------------------------
diff --git a/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/Resource.as b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/Resource.as
new file mode 100644
index 0000000..0ea7b85
--- /dev/null
+++ b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/Resource.as
@@ -0,0 +1,349 @@
+/*
+*  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.
+*
+*/
+package org.apache.flex.ant.tags.filesetClasses
+{
+    import flash.filesystem.FileStream;
+    import org.apache.flex.ant.tags.filesetClasses.exceptions.UnsupportedOperationException;
+    
+    /**
+     * Ported from org.apache.tools.ant.types.Resource.java on 12/3/13. 
+     * Describes a "File-like" resource (File, ZipEntry, etc.).
+     *
+     * This class is meant to be used by classes needing to record path
+     * and date/time information about a file, a zip entry or some similar
+     * resource (URL, archive in a version control repository, ...).
+     *
+     * @since Ant 1.5.2
+     * @see org.apache.tools.ant.types.resources.Touchable
+     */
+    public class Resource extends DataType
+    {
+        
+        /** Constant unknown size */
+        public static const UNKNOWN_SIZE:int = -1;
+        
+        /** Constant unknown datetime for getLastModified */
+        public static const UNKNOWN_DATETIME:int = 0;
+                
+        private var name:String;
+        private var exists:Boolean = true;
+        private var lastmodified:Number;
+        private var directory:Boolean;
+        private var _size:int;
+        private var nameSet:Boolean;
+        private var existsSet:Boolean;
+        private var lastmodifiedSet:Boolean;
+        private var directorySet:Boolean;
+        private var sizeSet:Boolean;
+        
+        
+        /**
+         * Sets the name, lastmodified flag, exists flag, directory flag, and size.
+         *
+         * @param name relative path of the resource.  Expects
+         * &quot;/&quot; to be used as the directory separator.
+         * @param exists if true the resource exists
+         * @param lastmodified the last modification time of the resource
+         * @param directory    if true, this resource is a directory
+         * @param size the size of this resource.
+         */
+        public function Resource(name:String, exists:Boolean  = false, lastmodified:Number = NaN, 
+                            directory:Boolean = false, size:int = UNKNOWN_SIZE) {
+            this.name = name;
+            setName(name);
+            setExists(exists);
+            setLastModified(lastmodified);
+            setDirectory(directory);
+            setSize(size);
+        }
+        
+        /**
+         * Name attribute will contain the path of a file relative to the
+         * root directory of its fileset or the recorded path of a zip
+         * entry.
+         *
+         * <p>example for a file with fullpath /var/opt/adm/resource.txt
+         * in a file set with root dir /var/opt it will be
+         * adm/resource.txt.</p>
+         *
+         * <p>&quot;/&quot; will be used as the directory separator.</p>
+         * @return the name of this resource.
+         */
+        public function getName():String  
+        {
+            return isReference() ? Resource(getCheckedRef()).getName() : name;
+        }
+        
+        /**
+         * Set the name of this Resource.
+         * @param name relative path of the resource.  Expects
+         * &quot;/&quot; to be used as the directory separator.
+         */
+        public function setName(name:String):void 
+        {
+            checkAttributesAllowed();
+            this.name = name;
+            nameSet = true;
+        }
+        
+        /**
+         * The exists attribute tells whether a resource exists.
+         * @return true if this resource exists.
+         */
+        public function isExists():Boolean 
+        {
+            if (isReference()) {
+                return Resource(getCheckedRef()).isExists();
+            }
+            //default true:
+            return exists;
+        }
+        
+        /**
+         * Set the exists attribute.
+         * @param exists if true, this resource exists.
+         */
+        public function setExists(exists:Boolean):void 
+        {
+            checkAttributesAllowed();
+            this.exists = exists;
+            existsSet = true;
+        }
+        
+        /**
+         * Tells the modification time in milliseconds since 01.01.1970 (the "epoch").
+         *
+         * @return the modification time, if that is meaningful
+         *            (e.g. for a file resource which exists);
+         *         0 if the resource does not exist, to mirror the behavior
+         *         of {@link java.io.File#lastModified};
+         *         or 0 if the notion of modification time is meaningless for this class
+         *           of resource (e.g. an inline string)
+         */
+        public function getLastModified():Number
+        {
+            if (isReference()) {
+                return Resource(getCheckedRef()).getLastModified();
+            }
+            if (!isExists() || !lastmodifiedSet) {
+                return UNKNOWN_DATETIME;
+            }
+            var result:Number = lastmodified;
+            return result < UNKNOWN_DATETIME ? UNKNOWN_DATETIME : result;
+        }
+        
+        /**
+         * Set the last modification attribute.
+         * @param lastmodified the modification time in milliseconds since 01.01.1970.
+         */
+        public function setLastModified(lastmodified:Number):void 
+        {
+            checkAttributesAllowed();
+            this.lastmodified = lastmodified;
+            lastmodifiedSet = true;
+        }
+        
+        /**
+         * Tells if the resource is a directory.
+         * @return boolean flag indicating if the resource is a directory.
+         */
+        public function isDirectory():Boolean 
+        {
+            if (isReference()) {
+                return Resource(getCheckedRef()).isDirectory();
+            }
+            //default false:
+            return directory;
+        }
+        
+        /**
+         * Set the directory attribute.
+         * @param directory if true, this resource is a directory.
+         */
+        public function setDirectory(directory:Boolean):void
+        {
+            checkAttributesAllowed();
+            this.directory = directory;
+            directorySet = true;
+        }
+        
+        /**
+         * Set the size of this Resource.
+         * @param size the size, as a long.
+         * @since Ant 1.6.3
+         */
+        public function setSize(size:int):void 
+        {
+            checkAttributesAllowed();
+            _size = size > UNKNOWN_SIZE ? size : UNKNOWN_SIZE;
+            sizeSet = true;
+        }
+        
+        /**
+         * Get the size of this Resource.
+         * @return the size, as a long, 0 if the Resource does not exist (for
+         *         compatibility with java.io.File), or UNKNOWN_SIZE if not known.
+         * @since Ant 1.6.3
+         */
+        public function getSize():int 
+        {
+            if (isReference()) {
+                return Resource(getCheckedRef()).getSize();
+            }
+            return isExists()
+            ? (sizeSet ? _size : UNKNOWN_SIZE)
+                : 0;
+        }
+                
+        /**
+         * Delegates to a comparison of names.
+         * @param other the object to compare to.
+         * @return a negative integer, zero, or a positive integer as this Resource
+         *         is less than, equal to, or greater than the specified Resource.
+         * @since Ant 1.6
+         */
+        public function compareTo(other:Resource):int {
+            if (isReference()) {
+                return Resource(getCheckedRef()).compareTo(other);
+            }
+            return toString().localeCompare(other.toString());
+        }
+        
+        /**
+         * Implement basic Resource equality.
+         * @param other the object to check against.
+         * @return true if the specified Object is equal to this Resource.
+         * @since Ant 1.7
+         */
+        public function equals(other:Object):Boolean {
+            if (isReference()) {
+                return getCheckedRef().equals(other);
+            }
+            return compareTo(Resource(other)) == 0;
+        }
+               
+        /**
+         * Get an InputStream for the Resource.
+         * @return an InputStream containing this Resource's content.
+         * @throws IOException if unable to provide the content of this
+         *         Resource as a stream.
+         * @throws UnsupportedOperationException if InputStreams are not
+         *         supported for this Resource type.
+         * @since Ant 1.7
+         */
+        public function getInputStream():FileStream
+        {
+            if (isReference()) {
+                return Resource(getCheckedRef()).getInputStream();
+            }
+            throw new UnsupportedOperationException();
+        }
+        
+        /**
+         * Get an OutputStream for the Resource.
+         * @return an OutputStream to which content can be written.
+         * @throws IOException if unable to provide the content of this
+         *         Resource as a stream.
+         * @throws UnsupportedOperationException if OutputStreams are not
+         *         supported for this Resource type.
+         * @since Ant 1.7
+         */
+        public function getOutputStream():FileStream
+        {
+            if (isReference()) {
+                return Resource(getCheckedRef()).getOutputStream();
+            }
+            throw new UnsupportedOperationException();
+        }
+        
+        /**
+         * Fulfill the ResourceCollection contract.
+         * @return an Iterator of Resources.
+         * @since Ant 1.7
+         */
+        public function iterator():Vector.<Resource> 
+        {
+            return isReference() ? Resource(getCheckedRef()).iterator()
+            : Vector.<Resource>([this]);
+        }
+        
+        /**
+         * Fulfill the ResourceCollection contract.
+         * @return the size of this ResourceCollection.
+         * @since Ant 1.7
+         */
+        public function size():int {
+            return isReference() ? Resource(getCheckedRef()).size() : 1;
+        }
+        
+        /**
+         * Fulfill the ResourceCollection contract.
+         * @return whether this Resource is a FileProvider.
+         * @since Ant 1.7
+         */
+        public function isFilesystemOnly():Boolean 
+        {
+            return (isReference() && Resource(getCheckedRef()).isFilesystemOnly())
+            || this is FileProvider;
+                }
+        
+        /**
+         * Get the string representation of this Resource.
+         * @return this Resource formatted as a String.
+         * @since Ant 1.7
+         */
+        override public function toString():String 
+        {
+            if (isReference()) {
+                return getCheckedRef().toString();
+            }
+            var n:String = getName();
+            return n == null ? "(anonymous)" : n;
+        }
+        
+        /**
+         * Get a long String representation of this Resource.
+         * This typically should be the value of <code>toString()</code>
+         * prefixed by a type description.
+         * @return this Resource formatted as a long String.
+         * @since Ant 1.7
+         */
+        public function toLongString():String 
+        {
+            return isReference() ? Resource(getCheckedRef()).toLongString()
+            : getDataTypeName() + " \"" + toString() + '"';
+        }
+        
+        /**
+         * Overrides the base version.
+         * @param r the Reference to set.
+         */
+        override public function setRefid(r:Reference):void 
+        {
+            if (nameSet
+                || existsSet
+                || lastmodifiedSet
+                || directorySet
+                || sizeSet) {
+                throw tooManyAttributes();
+            }
+            super.setRefid(r);
+        }
+        
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/f954e6f6/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/SelectorUtils.as
----------------------------------------------------------------------
diff --git a/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/SelectorUtils.as b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/SelectorUtils.as
new file mode 100644
index 0000000..de28992
--- /dev/null
+++ b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/SelectorUtils.as
@@ -0,0 +1,638 @@
+/*
+*  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.
+*
+*/
+
+package org.apache.flex.ant.tags.filesetClasses
+{
+    import flash.filesystem.File;
+    
+    /**
+     * Ported from org.apache.tools.ant.types.selectors.SelectorUtils.java on 12/03/13.
+     * <p>This is a utility class used by selectors and DirectoryScanner. The
+     * functionality more properly belongs just to selectors, but unfortunately
+     * DirectoryScanner exposed these as protected methods. Thus we have to
+     * support any subclasses of DirectoryScanner that may access these methods.
+     * </p>
+     * <p>This is a Singleton.</p>
+     *
+     * @since 1.5
+     */
+    public final class SelectorUtils 
+    {
+        
+        /**
+         * The pattern that matches an arbitrary number of directories.
+         * @since Ant 1.8.0
+         */
+        public static const DEEP_TREE_MATCH:String = "**";
+        
+        private static const instance:SelectorUtils = new SelectorUtils();
+        private static const FILE_UTILS:FileUtils = FileUtils.getFileUtils();
+        
+        /**
+         * Private Constructor
+         */
+        public function SelectorUtils() {
+        }
+        
+        /**
+         * Retrieves the instance of the Singleton.
+         * @return singleton instance
+         */
+        public static function getInstance():SelectorUtils {
+            return instance;
+        }
+        
+        /**
+         * Tests whether or not a given path matches the start of a given
+         * pattern up to the first "**".
+         * <p>
+         * This is not a general purpose test and should only be used if you
+         * can live with false positives. For example, <code>pattern=**\a</code>
+         * and <code>str=b</code> will yield <code>true</code>.
+         *
+         * @param pattern The pattern to match against. Must not be
+         *                <code>null</code>.
+         * @param str     The path to match, as a String. Must not be
+         *                <code>null</code>.
+         * @param isCaseSensitive Whether or not matching should be performed
+         *                        case sensitively.
+         *
+         * @return whether or not a given path matches the start of a given
+         * pattern up to the first "**".
+         */
+        public static function matchPatternStart(pattern:String, str:String,
+            isCaseSensitive:Boolean = true):Boolean  
+        {
+                // When str starts with a File.separator, pattern has to start with a
+                // File.separator.
+                // When pattern starts with a File.separator, str has to start with a
+                // File.separator.
+                if (str.indexOf(File.separator) == 0
+                    != pattern.indexOf(File.separator) == 0) {
+                    return false;
+                }
+                
+                var patDirs:Vector.<String> = tokenizePathAsArray(pattern);
+                var strDirs:Vector.<String> = tokenizePathAsArray(str);
+                return matchPatternStartVectors(patDirs, strDirs, isCaseSensitive);
+            }
+        
+        
+        /**
+         * Tests whether or not a given path matches the start of a given
+         * pattern up to the first "**".
+         * <p>
+         * This is not a general purpose test and should only be used if you
+         * can live with false positives. For example, <code>pattern=**\a</code>
+         * and <code>str=b</code> will yield <code>true</code>.
+         *
+         * @param patDirs The tokenized pattern to match against. Must not be
+         *                <code>null</code>.
+         * @param strDirs The tokenized path to match. Must not be
+         *                <code>null</code>.
+         * @param isCaseSensitive Whether or not matching should be performed
+         *                        case sensitively.
+         *
+         * @return whether or not a given path matches the start of a given
+         * pattern up to the first "**".
+         */
+        public static function matchPatternStartVectors(patDirs:Vector.<String>, 
+            strDirs:Vector.<String>,
+            isCaseSensitive:Boolean):Boolean {
+                var patIdxStart:int = 0;
+                var patIdxEnd:int = patDirs.length - 1;
+                var strIdxStart:int = 0;
+                var strIdxEnd:int = strDirs.length - 1;
+                
+                // up to first '**'
+                while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+                    var patDir:String = patDirs[patIdxStart];
+                    if (patDir == DEEP_TREE_MATCH) {
+                        break;
+                    }
+                    if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
+                        return false;
+                    }
+                    patIdxStart++;
+                    strIdxStart++;
+                }
+                
+                // CheckStyle:SimplifyBooleanReturnCheck OFF
+                // Check turned off as the code needs the comments for the various
+                // code paths.
+                if (strIdxStart > strIdxEnd) {
+                    // String is exhausted
+                    return true;
+                } else if (patIdxStart > patIdxEnd) {
+                    // String not exhausted, but pattern is. Failure.
+                    return false;
+                } else {
+                    // pattern now holds ** while string is not exhausted
+                    // this will generate false positives but we can live with that.
+                    return true;
+                }
+            }
+        
+        /**
+         * Tests whether or not a given path matches a given pattern.
+         *
+         * If you need to call this method multiple times with the same
+         * pattern you should rather use TokenizedPattern
+         *
+         * @see TokenizedPattern
+         *
+         * @param pattern The pattern to match against. Must not be
+         *                <code>null</code>.
+         * @param str     The path to match, as a String. Must not be
+         *                <code>null</code>.
+         * @param isCaseSensitive Whether or not matching should be performed
+         *                        case sensitively.
+         *
+         * @return <code>true</code> if the pattern matches against the string,
+         *         or <code>false</code> otherwise.
+         */
+        public static function matchPath(pattern:String, str:String,
+            isCaseSensitive:Boolean = true):Boolean
+        {
+            var patDirs:Vector.<String> = tokenizePathAsArray(pattern);
+            return matchPathVectors(patDirs, tokenizePathAsArray(str), isCaseSensitive);
+        }
+        
+        /**
+         * Core implementation of matchPath.  It is isolated so that it
+         * can be called from TokenizedPattern.
+         */
+        public static function matchPathVectors(tokenizedPattern:Vector.<String>, 
+            strDirs:Vector.<String>,
+            isCaseSensitive:Boolean):Boolean 
+        {
+                var patIdxStart:int = 0;
+                var patIdxEnd:int = tokenizedPattern.length - 1;
+                var strIdxStart:int = 0;
+                var strIdxEnd:int = strDirs.length - 1;
+                
+                // up to first '**'
+                while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+                    var patDir:String = tokenizedPattern[patIdxStart];
+                    if (patDir == DEEP_TREE_MATCH) {
+                        break;
+                    }
+                    if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
+                        return false;
+                    }
+                    patIdxStart++;
+                    strIdxStart++;
+                }
+                if (strIdxStart > strIdxEnd) {
+                    // String is exhausted
+                    for (i = patIdxStart; i <= patIdxEnd; i++) {
+                        if (tokenizedPattern[i] != DEEP_TREE_MATCH) {
+                            return false;
+                        }
+                    }
+                    return true;
+                } else {
+                    if (patIdxStart > patIdxEnd) {
+                        // String not exhausted, but pattern is. Failure.
+                        return false;
+                    }
+                }
+                
+                // up to last '**'
+                while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+                    patDir = tokenizedPattern[patIdxEnd];
+                    if (patDir == DEEP_TREE_MATCH) {
+                        break;
+                    }
+                    if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) {
+                        return false;
+                    }
+                    patIdxEnd--;
+                    strIdxEnd--;
+                }
+                if (strIdxStart > strIdxEnd) {
+                    // String is exhausted
+                    for (i = patIdxStart; i <= patIdxEnd; i++) {
+                        if (!tokenizedPattern[i] == DEEP_TREE_MATCH) {
+                            return false;
+                        }
+                    }
+                    return true;
+                }
+                
+                while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+                    var patIdxTmp:int = -1;
+                    for (i = patIdxStart + 1; i <= patIdxEnd; i++) {
+                        if (tokenizedPattern[i] ==  DEEP_TREE_MATCH) {
+                            patIdxTmp = i;
+                            break;
+                        }
+                    }
+                    if (patIdxTmp == patIdxStart + 1) {
+                        // '**/**' situation, so skip one
+                        patIdxStart++;
+                        continue;
+                    }
+                    // Find the pattern between padIdxStart & padIdxTmp in str between
+                    // strIdxStart & strIdxEnd
+                    var patLength:int = (patIdxTmp - patIdxStart - 1);
+                    var strLength:int = (strIdxEnd - strIdxStart + 1);
+                    var foundIdx:int = -1;
+                    strLoop:
+                    for (i = 0; i <= strLength - patLength; i++) {
+                        for (var j:int = 0; j < patLength; j++) {
+                            var subPat:String = tokenizedPattern[patIdxStart + j + 1];
+                            var subStr:String = strDirs[strIdxStart + i + j];
+                            if (!match(subPat, subStr, isCaseSensitive)) {
+                                continue strLoop;
+                            }
+                        }
+                        
+                        foundIdx = strIdxStart + i;
+                        break;
+                    }
+                    
+                    if (foundIdx == -1) {
+                        return false;
+                    }
+                    
+                    patIdxStart = patIdxTmp;
+                    strIdxStart = foundIdx + patLength;
+                }
+                
+                for (var i:int = patIdxStart; i <= patIdxEnd; i++) {
+                    if (!tokenizedPattern[i] == DEEP_TREE_MATCH) {
+                        return false;
+                    }
+                }
+                
+                return true;
+            }
+        
+        /**
+         * Tests whether or not a string matches against a pattern.
+         * The pattern may contain two special characters:<br>
+         * '*' means zero or more characters<br>
+         * '?' means one and only one character
+         *
+         * @param pattern The pattern to match against.
+         *                Must not be <code>null</code>.
+         * @param str     The string which must be matched against the pattern.
+         *                Must not be <code>null</code>.
+         * @param caseSensitive Whether or not matching should be performed
+         *                        case sensitively.
+         *
+         *
+         * @return <code>true</code> if the string matches against the pattern,
+         *         or <code>false</code> otherwise.
+         */
+        public static function match(pattern:String, str:String,
+            caseSensitive:Boolean = true):Boolean 
+        {
+                var patArr:Vector.<String> = Vector.<String>(pattern.split(""));
+                var strArr:Vector.<String> = Vector.<String>(str.split(""));
+                var patIdxStart:int = 0;
+                var patIdxEnd:int = patArr.length - 1;
+                var strIdxStart:int = 0;
+                var strIdxEnd:int = strArr.length - 1;
+                var ch:String;
+                
+                var containsStar:Boolean = false;
+                for (var i:int = 0; i < patArr.length; i++) {
+                    if (patArr[i] == '*') {
+                        containsStar = true;
+                        break;
+                    }
+                }
+                
+                if (!containsStar) {
+                    // No '*'s, so we make a shortcut
+                    if (patIdxEnd != strIdxEnd) {
+                        return false; // Pattern and string do not have the same size
+                    }
+                    for (i = 0; i <= patIdxEnd; i++) {
+                        ch = patArr[i];
+                        if (ch != '?') {
+                            if (different(caseSensitive, ch, strArr[i])) {
+                                return false; // Character mismatch
+                            }
+                        }
+                    }
+                    return true; // String matches against pattern
+                }
+                
+                if (patIdxEnd == 0) {
+                    return true; // Pattern contains only '*', which matches anything
+                }
+                
+                // Process characters before first star
+                while (true) {
+                    ch = patArr[patIdxStart];
+                    if (ch == '*' || strIdxStart > strIdxEnd) {
+                        break;
+                    }
+                    if (ch != '?') {
+                        if (different(caseSensitive, ch, strArr[strIdxStart])) {
+                            return false; // Character mismatch
+                        }
+                    }
+                    patIdxStart++;
+                    strIdxStart++;
+                }
+                if (strIdxStart > strIdxEnd) {
+                    // All characters in the string are used. Check if only '*'s are
+                    // left in the pattern. If so, we succeeded. Otherwise failure.
+                    return allStars(patArr, patIdxStart, patIdxEnd);
+                }
+                
+                // Process characters after last star
+                while (true) {
+                    ch = patArr[patIdxEnd];
+                    if (ch == '*' || strIdxStart > strIdxEnd) {
+                        break;
+                    }
+                    if (ch != '?') {
+                        if (different(caseSensitive, ch, strArr[strIdxEnd])) {
+                            return false; // Character mismatch
+                        }
+                    }
+                    patIdxEnd--;
+                    strIdxEnd--;
+                }
+                if (strIdxStart > strIdxEnd) {
+                    // All characters in the string are used. Check if only '*'s are
+                    // left in the pattern. If so, we succeeded. Otherwise failure.
+                    return allStars(patArr, patIdxStart, patIdxEnd);
+                }
+                
+                // process pattern between stars. padIdxStart and patIdxEnd point
+                // always to a '*'.
+                while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+                    var patIdxTmp:int = -1;
+                    for (i = patIdxStart + 1; i <= patIdxEnd; i++) {
+                        if (patArr[i] == '*') {
+                            patIdxTmp = i;
+                            break;
+                        }
+                    }
+                    if (patIdxTmp == patIdxStart + 1) {
+                        // Two stars next to each other, skip the first one.
+                        patIdxStart++;
+                        continue;
+                    }
+                    // Find the pattern between padIdxStart & padIdxTmp in str between
+                    // strIdxStart & strIdxEnd
+                    var patLength:int = (patIdxTmp - patIdxStart - 1);
+                    var strLength:int = (strIdxEnd - strIdxStart + 1);
+                    var foundIdx:int = -1;
+                    strLoop:
+                    for (i  = 0; i <= strLength - patLength; i++) {
+                        for (var j:int = 0; j < patLength; j++) {
+                            ch = patArr[patIdxStart + j + 1];
+                            if (ch != '?') {
+                                if (different(caseSensitive, ch,
+                                    strArr[strIdxStart + i + j])) {
+                                    continue strLoop;
+                                }
+                            }
+                        }
+                        
+                        foundIdx = strIdxStart + i;
+                        break;
+                    }
+                    
+                    if (foundIdx == -1) {
+                        return false;
+                    }
+                    
+                    patIdxStart = patIdxTmp;
+                    strIdxStart = foundIdx + patLength;
+                }
+                
+                // All characters in the string are used. Check if only '*'s are left
+                // in the pattern. If so, we succeeded. Otherwise failure.
+                return allStars(patArr, patIdxStart, patIdxEnd);
+            }
+        
+        private static function allStars(chars:Vector.<String>, start:int, end:int):Boolean 
+        {
+            for (var i:int = start; i <= end; ++i) {
+                if (chars[i] != '*') {
+                    return false;
+                }
+            }
+            return true;
+        }
+        
+        private static function different(
+            caseSensitive:Boolean, ch:String, other:String):Boolean 
+        {
+                return caseSensitive
+                ? ch != other
+                    : ch.toUpperCase() != other.toUpperCase();
+        }
+                    
+            /**
+             * Breaks a path up into a Vector of path elements, tokenizing on
+             *
+             * @param path Path to tokenize. Must not be <code>null</code>.
+             * @param separator the separator against which to tokenize.
+             *
+             * @return a Vector of path elements from the tokenized path
+             * @since Ant 1.6
+             */
+            public static function tokenizePath(path:String, 
+                         separator:String = null):Vector.<String>  
+            {
+                if (separator == null)
+                    separator = File.separator;
+                
+                var ret:Vector.<String> = new Vector.<String>();
+                if (FileUtils.isAbsolutePath(path)) {
+                    var s:Vector.<String> = FILE_UTILS.dissect(path);
+                    ret.push(s[0]);
+                    path = s[1];
+                }
+                var st:StringTokenizer = new StringTokenizer(path, separator);
+                while (st.hasMoreTokens()) {
+                    ret.push(st.nextToken());
+                }
+                return ret;
+            }
+                
+                /**
+                 * Same as {@link #tokenizePath tokenizePath} but hopefully faster.
+                 */
+                /*package*/public static function tokenizePathAsArray(path:String):Vector.<String> 
+                {
+                    var root:String = null;
+                    if (FileUtils.isAbsolutePath(path)) {
+                        var s:Vector.<String> = FILE_UTILS.dissect(path);
+                        root = s[0];
+                        path = s[1];
+                    }
+                    var sep:String = File.separator;
+                    var start:int = 0;
+                    var len:int = path.length;
+                    var count:int = 0;
+                    for (var pos:int = 0; pos < len; pos++) {
+                        if (path.charAt(pos) == sep) {
+                            if (pos != start) {
+                                count++;
+                            }
+                            start = pos + 1;
+                        }
+                    }
+                    if (len != start) {
+                        count++;
+                    }
+                    var l:Vector.<String> = Vector.<String>(new Array(count + ((root == null) ? 0 : 1)));
+                    
+                    if (root != null) {
+                        l[0] = root;
+                        count = 1;
+                    } else {
+                        count = 0;
+                    }
+                    start = 0;
+                    for (pos = 0; pos < len; pos++) {
+                        if (path.charAt(pos) == sep) {
+                            if (pos != start) {
+                                var tok:String = path.substring(start, pos);
+                                l[count++] = tok;
+                            }
+                            start = pos + 1;
+                        }
+                    }
+                    if (len != start) {
+                        tok = path.substring(start);
+                        l[count/*++*/] = tok;
+                    }
+                    return l;
+                }
+        
+        /**
+         * Returns dependency information on these two files. If src has been
+         * modified later than target, it returns true. If target doesn't exist,
+         * it likewise returns true. Otherwise, target is newer than src and
+         * is not out of date, thus the method returns false. It also returns
+         * false if the src file doesn't even exist, since how could the
+         * target then be out of date.
+         *
+         * @param src the original file
+         * @param target the file being compared against
+         * @param granularity the amount in seconds of slack we will give in
+         *        determining out of dateness
+         * @return whether the target is out of date
+         */
+        private static function isOutOfDateFile(src:File, target:File, granularity:int):Boolean {
+            if (!src.exists) {
+                return false;
+            }
+            if (!target.exists) {
+                return true;
+            }
+            if ((src.modificationDate.time - granularity) > target.modificationDate.time) {
+                return true;
+            }
+            return false;
+        }
+        
+        /**
+         * Returns dependency information on these two resources. If src has been
+         * modified later than target, it returns true. If target doesn't exist,
+         * it likewise returns true. Otherwise, target is newer than src and
+         * is not out of date, thus the method returns false. It also returns
+         * false if the src file doesn't even exist, since how could the
+         * target then be out of date.
+         *
+         * @param src the original resource
+         * @param target the resource being compared against
+         * @param granularity the int amount in seconds of slack we will give in
+         *        determining out of dateness
+         * @return whether the target is out of date
+         */
+        public static function isOutOfDate(src:Object, target:Object,
+            granularity:int):Boolean {
+                if (src is File)
+                    return isOutOfDateFile(src as File, target as File, granularity);
+                return isOutOfDateResource(src as Resource, target as Resource, granularity);
+            }
+        
+        /**
+         * Returns dependency information on these two resources. If src has been
+         * modified later than target, it returns true. If target doesn't exist,
+         * it likewise returns true. Otherwise, target is newer than src and
+         * is not out of date, thus the method returns false. It also returns
+         * false if the src file doesn't even exist, since how could the
+         * target then be out of date.
+         *
+         * @param src the original resource
+         * @param target the resource being compared against
+         * @param granularity the long amount in seconds of slack we will give in
+         *        determining out of dateness
+         * @return whether the target is out of date
+         */
+        private static function isOutOfDateResource(src:Resource, target:Resource,
+                                           granularity:int):Boolean {
+            var sourceLastModified:Number = src.getLastModified();
+            var targetLastModified:Number = target.getLastModified();
+            return src.isExists()
+                && (sourceLastModified == Resource.UNKNOWN_DATETIME
+                    || targetLastModified == Resource.UNKNOWN_DATETIME
+                    || (sourceLastModified - granularity) > targetLastModified);
+        }
+        
+        /**
+         * "Flattens" a string by removing all whitespace (space, tab, linefeed,
+         * carriage return, and formfeed). This uses StringTokenizer and the
+         * default set of tokens as documented in the single argument constructor.
+         *
+         * @param input a String to remove all whitespace.
+         * @return a String that has had all whitespace removed.
+         */
+        public static function removeWhitespace(input:String):String {
+            var result:String = "";
+            if (input != null) {
+                var st:StringTokenizer = new StringTokenizer(input);
+                while (st.hasMoreTokens()) {
+                    result += st.nextToken();
+                }
+            }
+            return result;
+        }
+        
+        /**
+         * Tests if a string contains stars or question marks
+         * @param input a String which one wants to test for containing wildcard
+         * @return true if the string contains at least a star or a question mark
+         */
+        public static function hasWildcards(input:String):Boolean {
+            return (input.indexOf('*') != -1 || input.indexOf('?') != -1);
+        }
+        
+        /**
+         * removes from a pattern all tokens to the right containing wildcards
+         * @param input the input string
+         * @return the leftmost part of the pattern without wildcards
+         */
+        public static function rtrimWildcardTokens(input:String):String {
+            return new TokenizedPattern(input).rtrimWildcardTokens().toString();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/f954e6f6/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/StringTokenizer.as
----------------------------------------------------------------------
diff --git a/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/StringTokenizer.as b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/StringTokenizer.as
new file mode 100644
index 0000000..02ddff5
--- /dev/null
+++ b/flex-installer/ant_on_air/src/org/apache/flex/ant/tags/filesetClasses/StringTokenizer.as
@@ -0,0 +1,74 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.
+//
+////////////////////////////////////////////////////////////////////////////////
+package org.apache.flex.ant.tags.filesetClasses
+{
+    // an approximation of the Java StringTokenizer
+    public class StringTokenizer
+    {
+        public function StringTokenizer(s:String, delims:String = "\t\r\n\f", returnDelims:Boolean = false)
+        {
+            tokens = new Vector.<String>();
+            var c1:int = 0;
+            var c2:int = 0;
+            var n:int = s.length;
+            while (c2 < n)
+            {
+                var c:String = s.charAt(c2);
+                if (delims.indexOf(c) != -1)
+                {
+                    tokens.push(s.substring(c1, c2));
+                    c1 = c2;
+                    while (c2 < n)
+                    {
+                        c = s.charAt(c2);
+                        if (delims.indexOf(c) == -1)
+                        {
+                            if (returnDelims)
+                                tokens.push(s.substring(c1, c2))
+                            c1 = c2;
+                            break;
+                        }
+                        c2++;
+                    }
+                    if (returnDelims && c1 < c2)
+                    {
+                        tokens.push(s.substring(c1, c2));
+                        c1 = c2;
+                    }
+                }
+                c2++;
+            }
+            if (c1 < n)
+                tokens.push(s.substring(c1))
+        }
+        
+        private var tokens:Vector.<String>;
+        private var index:int = 0;
+        
+        public function hasMoreTokens():Boolean
+        {
+            return index < tokens.length;    
+        }
+        
+        public function nextToken():String
+        {
+            return tokens[index++];
+        }
+    }
+}
\ No newline at end of file


Mime
View raw message