View Javadoc
1   /*
2    * Copyright (c) 2001, 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 build.tools.stripproperties;
27  
28  import java.io.BufferedInputStream;
29  import java.io.BufferedWriter;
30  import java.io.FileInputStream;
31  import java.io.FileNotFoundException;
32  import java.io.FileOutputStream;
33  import java.io.OutputStream;
34  import java.io.OutputStreamWriter;
35  import java.io.IOException;
36  import java.io.InputStream;
37  import java.util.ArrayList;
38  import java.util.Enumeration;
39  import java.util.Iterator;
40  import java.util.List;
41  import java.util.Properties;
42  
43  /**
44   * Reads a properties file from standard input and writes an equivalent
45   * properties file without comments to standard output.
46   */
47  public class StripProperties {
48  
49      private static void error(String msg, Exception e) {
50          System.err.println("ERROR: stripproperties: " + msg);
51          if ( e != null ) {
52              System.err.println("EXCEPTION: " + e.toString());
53              e.printStackTrace();
54          }
55      }
56  
57      private static List<String> infiles = new ArrayList<String>();
58      private static List<String> outfiles = new ArrayList<String>();
59  
60      private static boolean parseOptions(String args[]) {
61          boolean ok = true;
62  
63          for ( int i = 0; i < args.length ; i++ ) {
64              if ( "-clean".equals(args[i]) && i+2 < args.length ) {
65                  infiles.add(args[++i]);
66                  outfiles.add(args[++i]);
67              } else if ( args[i].charAt(0)=='@') {
68                  String filename = args[i].substring(1);
69                  FileInputStream finput = null;
70                  byte contents[] = null;
71                  try {
72                      finput = new FileInputStream(filename);
73                      int byteCount = finput.available();
74                      if ( byteCount <= 0 ) {
75                          error("The @file is empty", null);
76                          ok = false;
77                      } else {
78                          contents = new byte[byteCount];
79                          int bytesRead = finput.read(contents);
80                          if ( byteCount != bytesRead ) {
81                              error("Cannot read all of @file", null);
82                              ok = false;
83                          }
84                      }
85                  } catch ( IOException e ) {
86                      error("cannot open " + filename, e);
87                      ok = false;
88                  }
89                  if ( finput != null ) {
90                      try {
91                          finput.close();
92                      } catch ( IOException e ) {
93                          ok = false;
94                          error("cannot close " + filename, e);
95                      }
96                  }
97                  if ( ok && contents != null ) {
98                      String tokens[] = (new String(contents)).split("\\s+");
99                      if ( tokens.length > 0 ) {
100                         ok = parseOptions(tokens);
101                     }
102                 }
103                 if ( !ok ) {
104                     break;
105                 }
106             } else {
107                 infiles.add(args[i]);
108                 outfiles.add(args[i]);
109             }
110         }
111         return ok;
112     }
113 
114     private static boolean stripFiles(List<String> infiles, List<String> outfiles) {
115         boolean ok = true;
116         Iterator<String> inIter  = infiles.iterator();
117         Iterator<String> outIter = outfiles.iterator();
118 
119         for (; inIter.hasNext(); ) {
120             String infile = inIter.next();
121             String outfile = outIter.next();
122 
123             Properties prop = new Properties();
124             InputStream in = null;
125             try {
126                 in = new BufferedInputStream(new FileInputStream(infile));
127                 prop.load(in);
128             } catch ( FileNotFoundException e ) {
129                 error("Cannot access file " + infile, e);
130                 ok = false;
131             } catch ( IOException e ) {
132                 error("IO exception processing file " + infile, e);
133                 ok = false;
134             }
135             if ( in != null ) {
136                 try {
137                     in.close();
138                 } catch ( IOException e ) {
139                     error("IO exception closing file " + infile, e);
140                     ok = false;
141                 }
142             }
143             if ( !ok ) {
144                 break;
145             }
146 
147             OutputStream out = null;
148             try {
149                 out = new FileOutputStream(outfile);
150                 storeProperties(prop, out);
151                 out.flush();
152             } catch ( IOException e ) {
153                 error("IO exception processing file " + outfile, e);
154                 ok = false;
155             }
156             if ( out != null ) {
157                 try {
158                     out.close();
159                 } catch ( IOException e ) {
160                     error("IO exception closing file " + outfile, e);
161                     ok = false;
162                 }
163             }
164             if ( !ok ) {
165                 break;
166             }
167 
168         }
169         return ok;
170     }
171 
172     /**
173      * Strip the properties filenames supplied, replacing their contents.
174      * @param args Names of properties files to process and replace contents
175      */
176     public static void main(String args[]) {
177         boolean ok = parseOptions(args);
178         if ( !ok || !stripFiles(infiles, outfiles) ) {
179             System.exit(1);
180         }
181     }
182 
183     // --- code below here is adapted from java.util.Properties ---
184 
185     private static final String specialSaveChars = "=: \t\r\n\f#!";
186 
187     /*
188      * Converts unicodes to encoded &#92;uxxxx
189      * and writes out any of the characters in specialSaveChars
190      * with a preceding slash
191      */
192     private static String saveConvert(String theString, boolean escapeSpace) {
193         int len = theString.length();
194         StringBuffer outBuffer = new StringBuffer(len*2);
195 
196         for(int x=0; x<len; x++) {
197             char aChar = theString.charAt(x);
198             switch(aChar) {
199                 case ' ':
200                     if (x == 0 || escapeSpace) {
201                         outBuffer.append('\\');
202                     }
203                     outBuffer.append(' ');
204                     break;
205                 case '\\':
206                     outBuffer.append('\\');
207                     outBuffer.append('\\');
208                     break;
209                 case '\t':
210                     outBuffer.append('\\');
211                     outBuffer.append('t');
212                     break;
213                 case '\n':
214                     outBuffer.append('\\');
215                     outBuffer.append('n');
216                     break;
217                 case '\r':
218                     outBuffer.append('\\');
219                     outBuffer.append('r');
220                     break;
221                 case '\f':
222                     outBuffer.append('\\');
223                     outBuffer.append('f');
224                     break;
225                 default:
226                     if ((aChar < 0x0020) || (aChar == 0x007e) || (aChar > 0x00ff)) {
227                         outBuffer.append('\\');
228                         outBuffer.append('u');
229                         outBuffer.append(toHex((aChar >> 12) & 0xF));
230                         outBuffer.append(toHex((aChar >>  8) & 0xF));
231                         outBuffer.append(toHex((aChar >>  4) & 0xF));
232                         outBuffer.append(toHex( aChar        & 0xF));
233                     } else {
234                         if (specialSaveChars.indexOf(aChar) != -1) {
235                             outBuffer.append('\\');
236                         }
237                         outBuffer.append(aChar);
238                     }
239             }
240         }
241         return outBuffer.toString();
242     }
243 
244     /**
245      * Writes the content of <code>properties</code> to <code>out</code>.
246      * The format is that of Properties.store with the following modifications:
247      * <ul>
248      * <li>No header or date is written
249      * <li>Latin-1 characters are written as single bytes, not escape sequences
250      * <li>Line breaks are indicated by a single \n independent of platform
251      * <ul>
252      */
253     private static void storeProperties(Properties properties, OutputStream out)
254     throws IOException {
255         BufferedWriter awriter;
256         awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1"));
257         for (Enumeration<Object> e = properties.keys(); e.hasMoreElements();) {
258             String key = (String)e.nextElement();
259             String val = (String)properties.get(key);
260             key = saveConvert(key, true);
261 
262             /* No need to escape embedded and trailing spaces for value, hence
263              * pass false to flag.
264              */
265             val = saveConvert(val, false);
266             writeln(awriter, key + "=" + val);
267         }
268         awriter.flush();
269     }
270 
271     private static void writeln(BufferedWriter bw, String s) throws IOException {
272         bw.write(s);
273         bw.write("\n");
274     }
275 
276     /**
277      * Convert a nibble to a hex character
278      * @param   nibble  the nibble to convert.
279      */
280     private static char toHex(int nibble) {
281         return hexDigit[(nibble & 0xF)];
282     }
283 
284     /** A table of hex digits */
285     private static final char[] hexDigit = {
286         '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
287     };
288 }