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