1 /* 2 * Copyright (c) 2011, 2014, 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 class PackagerResource { 31 private static final ResourceFilter ACCEPT_ALL_FILTER = 32 new ResourceFilter() { 33 @Override 34 public boolean descent(final File file, 35 final String relativePath) { 36 return true; 37 } 38 39 @Override 40 public boolean accept(final File file, 41 final String relativePath) { 42 return true; 43 } 44 }; 45 46 private final File baseDir; 47 private final File file; 48 private final String relativePath; 49 50 public PackagerResource(final File baseDir, final String path) { 51 this(baseDir, createFile(baseDir, path)); 52 } 53 54 public PackagerResource(final File baseDir, final File file) { 55 final File nrmFile = normalizeFile(file); 56 if (nrmFile == null) { 57 throw new IllegalArgumentException("Invalid file specified"); 58 } 59 60 if (baseDir != null) { 61 final File nrmBaseDir = normalizeFile(baseDir); 62 if (nrmBaseDir == null) { 63 throw new IllegalArgumentException("Invalid basedir specified"); 64 } 65 66 if (nrmFile.equals(nrmBaseDir)) { 67 this.file = nrmFile; 68 this.baseDir = nrmFile; 69 this.relativePath = ""; 70 return; 71 } 72 73 final StringBuilder relativePathBuilder = 74 new StringBuilder(nrmFile.getName()); 75 76 File tempFile = nrmFile.getParentFile(); 77 while (tempFile != null) { 78 if (tempFile.equals(nrmBaseDir)) { 79 this.file = nrmFile; 80 this.baseDir = nrmBaseDir; 81 this.relativePath = relativePathBuilder.toString(); 82 return; 83 } 84 85 relativePathBuilder.insert(0, '/'); 86 relativePathBuilder.insert(0, tempFile.getName()); 87 tempFile = tempFile.getParentFile(); 88 } 89 } 90 91 final File nrmParentFile = nrmFile.getParentFile(); 92 93 this.file = nrmFile; 94 this.baseDir = (nrmParentFile != null) ? nrmParentFile : nrmFile; 95 this.relativePath = nrmFile.getName(); 96 } 97 98 public final File getBaseDir() { 99 return baseDir; 100 } 101 102 public final File getFile() { 103 return file; 104 } 105 106 public final String getRelativePath() { 107 return relativePath; 108 } 109 110 public final boolean traverse(final ResourceTraversal resourceTraversal) { 111 return traverse(resourceTraversal, null); 112 } 113 114 public final boolean traverse(final ResourceTraversal resourceTraversal, 115 final ResourceFilter resourceFilter) { 116 return new TraversalOperation((resourceFilter != null) 117 ? resourceFilter 118 : ACCEPT_ALL_FILTER, 119 resourceTraversal, this).execute(); 120 } 121 122 private static File normalizeFile(final File inputFile) { 123 return normalizeFileImpl(inputFile.getAbsoluteFile()); 124 } 125 126 private static File normalizeFileImpl(final File inputFile) { 127 if (inputFile.getParentFile() == null) { 128 return inputFile; 129 } 130 131 final File partiallyNormalizedFile = 132 normalizeFileImpl(inputFile.getParentFile()); 133 134 if (partiallyNormalizedFile == null) { 135 // error 136 return null; 137 } 138 139 final String fileName = inputFile.getName(); 140 141 if (fileName.equals(".")) { 142 // ignore this path element 143 return partiallyNormalizedFile; 144 } 145 146 if (fileName.equals("..")) { 147 // remove the last path element 148 return partiallyNormalizedFile.getParentFile(); 149 } 150 151 return new File(partiallyNormalizedFile, fileName); 152 } 153 154 private static File createFile(final File baseDir, final String path) { 155 final File testFile = new File(path); 156 return testFile.isAbsolute() 157 ? testFile 158 : new File(baseDir == null 159 ? null 160 : baseDir.getAbsolutePath(), 161 path); 162 } 163 164 private static final class TraversalOperation { 165 private final ResourceFilter resourceFilter; 166 private final ResourceTraversal resourceTraversal; 167 private final PackagerResource rootResource; 168 private final StringBuilder relativePathBuilder; 169 170 public TraversalOperation(final ResourceFilter resourceFilter, 171 final ResourceTraversal resourceTraversal, 172 final PackagerResource rootResource) { 173 this.resourceFilter = resourceFilter; 174 this.resourceTraversal = resourceTraversal; 175 this.rootResource = rootResource; 176 this.relativePathBuilder = 177 new StringBuilder(rootResource.relativePath); 178 } 179 180 public boolean execute() { 181 return traverse(rootResource.file); 182 } 183 184 private boolean traverse(final File file) { 185 final String relativePath = relativePathBuilder.toString(); 186 if (resourceFilter.accept(file, relativePath) 187 && !resourceTraversal.traverse(rootResource, file, 188 relativePath)) { 189 return false; 190 } 191 192 if (!file.isDirectory() 193 || !resourceFilter.descent(file, relativePath)) { 194 return true; 195 } 196 197 final int resetLength = relativePathBuilder.length(); 198 File[] children = file.listFiles(); 199 if (children != null) { 200 for (final File nextFile : children) { 201 if (resetLength > 0) { 202 relativePathBuilder.append('/'); 203 } 204 relativePathBuilder.append(nextFile.getName()); 205 if (!traverse(nextFile)) { 206 return false; 207 } 208 relativePathBuilder.setLength(resetLength); 209 } 210 } 211 212 return true; 213 } 214 } 215 }