1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.tools.resource;
  27 
  28 import java.io.File;
  29 
  30 public abstract class DetailedResourceTraversal implements ResourceTraversal {
  31     private String lastRelativePath;
  32 
  33     private boolean lastIsDirectory;
  34 
  35     public DetailedResourceTraversal() {
  36         lastRelativePath = "";
  37         lastIsDirectory = true;
  38     }
  39 
  40     public final boolean traverse(final PackagerResource rootResource,
  41                                   final File file,
  42                                   final String relativePath) {
  43         final boolean isDirectory = file.isDirectory();
  44         if (!traverseBetween(lastRelativePath, lastIsDirectory,
  45                              relativePath, isDirectory)) {
  46             return false;
  47         }
  48 
  49         lastRelativePath = relativePath;
  50         lastIsDirectory = isDirectory;
  51 
  52         return isDirectory ? true
  53                            : traverseFile(rootResource, file, relativePath);
  54     }
  55 
  56     public final void finish() {
  57         traverseBetween(lastRelativePath, lastIsDirectory, "", true);
  58 
  59         lastRelativePath = "";
  60         lastIsDirectory = true;
  61     }
  62 
  63     protected abstract boolean enterDirectory(String relativePath);
  64 
  65     protected abstract boolean exitDirectory(String relativePath);
  66 
  67     protected abstract boolean traverseFile(PackagerResource rootResource,
  68                                             File file,
  69                                             String relativePath);
  70 
  71     private boolean traverseBetween(final String relPath1,
  72                                     final boolean isDirectory1,
  73                                     final String relPath2,
  74                                     final boolean isDirectory2) {
  75         final int commonPathLength = getCommonPathLength(relPath1, relPath2);
  76 
  77         return traverseDown(relPath1, isDirectory1, commonPathLength)
  78                    && traverseUp(relPath2, isDirectory2, commonPathLength);
  79     }
  80 
  81     private boolean traverseDown(final String relPath,
  82                                  final boolean isDirectory,
  83                                  final int commonPathLength) {
  84         if (relPath.length() == commonPathLength) {
  85             return true;
  86         }
  87 
  88         if (isDirectory && !exitDirectory(relPath)) {
  89             return false;
  90         }
  91 
  92         int prevSeparator = findPrevSeparator(relPath, relPath.length() - 1,
  93                                               commonPathLength);
  94 
  95         while (prevSeparator > commonPathLength) {
  96             if (!exitDirectory(relPath.substring(0, prevSeparator))) {
  97                 return false;
  98             }
  99 
 100             prevSeparator = findPrevSeparator(relPath, prevSeparator - 1,
 101                                               commonPathLength);
 102         }
 103 
 104         return true;
 105     }
 106 
 107     private boolean traverseUp(final String relPath,
 108                                final boolean isDirectory,
 109                                final int commonPathLength) {
 110         if (relPath.length() == commonPathLength) {
 111             return true;
 112         }
 113 
 114         final int pathLength = relPath.length();
 115 
 116         int nextSeparator = findNextSeparator(relPath, commonPathLength + 1,
 117                                               pathLength);
 118 
 119         while (nextSeparator < pathLength) {
 120             if (!enterDirectory(relPath.substring(0, nextSeparator))) {
 121                 return false;
 122             }
 123 
 124             nextSeparator = findNextSeparator(relPath, nextSeparator + 1,
 125                                               pathLength);
 126         }
 127 
 128         if (isDirectory && !enterDirectory(relPath)) {
 129             return false;
 130         }
 131 
 132         return true;
 133     }
 134 
 135     private static int findPrevSeparator(final String relPath,
 136                                          final int fromIndex,
 137                                          final int minIndex) {
 138         final int prevSeparator = relPath.lastIndexOf('/', fromIndex);
 139         return (prevSeparator < minIndex) ? minIndex : prevSeparator;
 140     }
 141 
 142     private static int findNextSeparator(final String relPath,
 143                                          final int fromIndex,
 144                                          final int maxIndex) {
 145         final int nextSeparator = relPath.indexOf('/', fromIndex);
 146         return ((nextSeparator == -1) || (nextSeparator > maxIndex))
 147                        ? maxIndex : nextSeparator;
 148     }
 149 
 150     private static int getCommonPathLength(final String relPath1,
 151                                            final String relPath2) {
 152         final char[] path1Chars = relPath1.toCharArray();
 153         final char[] path2Chars = relPath2.toCharArray();
 154 
 155         int lastMatchIndex = 0;
 156         int i;
 157         for (i = 0; (i < path1Chars.length)
 158                         && (i < path2Chars.length)
 159                         && (path1Chars[i] == path2Chars[i]); ++i) {
 160             if (path1Chars[i] == '/') {
 161                 lastMatchIndex = i;
 162             }
 163         }
 164 
 165         if (i == path1Chars.length) {
 166             if ((i == path2Chars.length) || (path2Chars[i] == '/')) {
 167                 lastMatchIndex = i;
 168             }
 169         } else if ((i == path2Chars.length) && (path1Chars[i] == '/')) {
 170             lastMatchIndex = i;
 171         }
 172 
 173         return lastMatchIndex;
 174     }
 175 }