1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard; 22 23 import java.io.File; 24 25 /** 26 * This class checks whether the output is up to date. 27 * 28 * @author Eric Lafortune 29 */ 30 public class UpToDateChecker 31 { 32 private final Configuration configuration; 33 34 35 /** 36 * Creates a new UpToDateChecker with the given configuration. 37 */ UpToDateChecker(Configuration configuration)38 public UpToDateChecker(Configuration configuration) 39 { 40 this.configuration = configuration; 41 } 42 43 44 /** 45 * Returns whether the output is up to date, based on the modification times 46 * of the input jars, output jars, and library jars (or directories). 47 */ check()48 public boolean check() 49 { 50 try 51 { 52 ModificationTimeChecker checker = new ModificationTimeChecker(); 53 54 checker.updateInputModificationTime(configuration.lastModified); 55 56 ClassPath programJars = configuration.programJars; 57 ClassPath libraryJars = configuration.libraryJars; 58 59 // Check the dates of the program jars, if any. 60 if (programJars != null) 61 { 62 for (int index = 0; index < programJars.size(); index++) 63 { 64 // Update the input and output modification times. 65 ClassPathEntry classPathEntry = programJars.get(index); 66 67 checker.updateModificationTime(classPathEntry.getFile(), 68 classPathEntry.isOutput()); 69 } 70 } 71 72 // Check the dates of the library jars, if any. 73 if (libraryJars != null) 74 { 75 for (int index = 0; index < libraryJars.size(); index++) 76 { 77 // Update the input modification time. 78 ClassPathEntry classPathEntry = libraryJars.get(index); 79 80 checker.updateModificationTime(classPathEntry.getFile(), 81 false); 82 } 83 } 84 85 // Check the dates of the auxiliary input files. 86 checker.updateInputModificationTime(configuration.applyMapping); 87 checker.updateInputModificationTime(configuration.obfuscationDictionary); 88 checker.updateInputModificationTime(configuration.classObfuscationDictionary); 89 checker.updateInputModificationTime(configuration.packageObfuscationDictionary); 90 91 // Check the dates of the auxiliary output files. 92 checker.updateOutputModificationTime(configuration.printSeeds); 93 checker.updateOutputModificationTime(configuration.printUsage); 94 checker.updateOutputModificationTime(configuration.printMapping); 95 checker.updateOutputModificationTime(configuration.printConfiguration); 96 checker.updateOutputModificationTime(configuration.dump); 97 } 98 catch (IllegalStateException e) 99 { 100 // The output is outdated. 101 return false; 102 } 103 104 System.out.println("The output seems up to date"); 105 106 return true; 107 } 108 109 110 /** 111 * This class maintains the modification times of input and output. 112 * The methods throw an IllegalStateException if the output appears 113 * outdated. 114 */ 115 private static class ModificationTimeChecker { 116 117 private long inputModificationTime = Long.MIN_VALUE; 118 private long outputModificationTime = Long.MAX_VALUE; 119 120 121 /** 122 * Updates the input modification time based on the given file or 123 * directory (recursively). 124 */ updateInputModificationTime(File file)125 public void updateInputModificationTime(File file) 126 { 127 if (file != null) 128 { 129 updateModificationTime(file, false); 130 } 131 } 132 133 134 /** 135 * Updates the input modification time based on the given file or 136 * directory (recursively). 137 */ updateOutputModificationTime(File file)138 public void updateOutputModificationTime(File file) 139 { 140 if (file != null && file.getName().length() > 0) 141 { 142 updateModificationTime(file, true); 143 } 144 } 145 146 147 /** 148 * Updates the specified modification time based on the given file or 149 * directory (recursively). 150 */ updateModificationTime(File file, boolean isOutput)151 public void updateModificationTime(File file, boolean isOutput) 152 { 153 // Is it a directory? 154 if (file.isDirectory()) 155 { 156 // Ignore the directory's modification time; just recurse on 157 // its files. 158 File[] files = file.listFiles(); 159 160 // Still, an empty output directory is probably a sign that it 161 // is not up to date. 162 if (files.length == 0 && isOutput) 163 { 164 updateOutputModificationTime(Long.MIN_VALUE); 165 } 166 167 for (int index = 0; index < files.length; index++) 168 { 169 updateModificationTime(files[index], isOutput); 170 } 171 } 172 else 173 { 174 // Update with the file's modification time. 175 updateModificationTime(file.lastModified(), isOutput); 176 } 177 } 178 179 180 /** 181 * Updates the specified modification time. 182 */ updateModificationTime(long time, boolean isOutput)183 public void updateModificationTime(long time, boolean isOutput) 184 { 185 if (isOutput) 186 { 187 updateOutputModificationTime(time); 188 } 189 else 190 { 191 updateInputModificationTime(time); 192 } 193 } 194 195 196 /** 197 * Updates the input modification time. 198 */ updateInputModificationTime(long time)199 public void updateInputModificationTime(long time) 200 { 201 if (inputModificationTime < time) 202 { 203 inputModificationTime = time; 204 205 checkModificationTimes(); 206 } 207 } 208 209 210 /** 211 * Updates the output modification time. 212 */ updateOutputModificationTime(long time)213 public void updateOutputModificationTime(long time) 214 { 215 if (outputModificationTime > time) 216 { 217 outputModificationTime = time; 218 219 checkModificationTimes(); 220 } 221 } 222 223 checkModificationTimes()224 private void checkModificationTimes() 225 { 226 if (inputModificationTime > outputModificationTime) 227 { 228 throw new IllegalStateException("The output is outdated"); 229 } 230 } 231 } 232 } 233