Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/eireneh/util/PropertiesUtil.java


1   
2   package com.eireneh.util;
3   
4   import java.util.*;
5   import java.io.*;
6   
7   import com.eireneh.util.*;
8   
9   /**
10   * A generic class of Properties utils.
11   * It would be good if we could put this stuff in java.lang ...
12   *
13   * <table border='1' cellPadding='3' cellSpacing='0' width="100%">
14   * <tr><td bgColor='white'class='TableRowColor'><font size='-7'>
15   * Distribution Licence:<br />
16   * Project B is free software; you can redistribute it
17   * and/or modify it under the terms of the GNU General Public License,
18   * version 2 as published by the Free Software Foundation.<br />
19   * This program is distributed in the hope that it will be useful,
20   * but WITHOUT ANY WARRANTY; without even the implied warranty of
21   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22   * General Public License for more details.<br />
23   * The License is available on the internet
24   * <a href='http://www.gnu.org/copyleft/gpl.html'>here</a>, by writing to
25   * <i>Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26   * MA 02111-1307, USA</i>, Or locally at the Licence link below.<br />
27   * The copyright to this program is held by it's authors.
28   * </font></td></tr></table>
29   * @see <a href='http://www.eireneh.com/servlets/Web'>Project B Home</a>
30   * @see docs.Licence
31   * @author Joe Walker
32   */
33  public class PropertiesUtil
34  {
35      /**
36       * Write a Properties to a Stream an leave the stream in tact
37       */
38      public static void save(Properties prop, OutputStream out, String title) throws IOException
39      {
40          // In JDK 1.2 this should change to store. The quashed exception
41          // problem is probably not an issue here, since it would get
42          // re-raised by the following line.
43          saveInternal(prop, out, title);
44          out.write((DONE+SEPARATOR).getBytes());
45      }
46  
47      /**
48       * Writes this property list (key and element pairs) in this
49       * <code>Properties</code> table to the output stream in a format suitable
50       * for loading into a <code>Properties</code> table using the
51       * <code>load</code> method.
52       * @param out an output stream.
53       * @param header a description of the property list.
54       */
55      private static synchronized void saveInternal(Properties prop, OutputStream out, String header) throws IOException
56      {
57          BufferedWriter awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1"));
58          if (header != null)
59              writeln(awriter, "#" + header);
60  
61          writeln(awriter, "#" + new Date().toString());
62          for (Enumeration e = prop.keys(); e.hasMoreElements();)
63          {
64              String key = (String) e.nextElement();
65              String val = (String) prop.get(key);
66              key = saveConvert(key);
67              val = saveConvert(val);
68              writeln(awriter, key + "=" + val);
69          }
70          awriter.flush();
71      }
72  
73      /**
74       * Write a line to a file
75       */
76      private static void writeln(BufferedWriter bw, String s) throws IOException
77      {
78          bw.write(s);
79          bw.newLine();
80      }
81  
82      /**
83       * Converts unicodes to encoded \\uxxxx
84       * and writes out any of the characters in specialSaveChars
85       * with a preceding slash
86       */
87      private static String saveConvert(String theString)
88      {
89          char aChar;
90          int len = theString.length();
91          StringBuffer outBuffer = new StringBuffer(len*2);
92  
93          for (int x=0; x<len; )
94          {
95              aChar = theString.charAt(x++);
96              switch (aChar)
97              {
98              case '\\':
99                  outBuffer.append('\\');
100                 outBuffer.append('\\');
101                 continue;
102 
103             case '\t':
104                 outBuffer.append('\\');
105                 outBuffer.append('t');
106                 continue;
107 
108             case '\n':
109                 outBuffer.append('\\');
110                 outBuffer.append('n');
111                 continue;
112 
113             case '\r':
114                 outBuffer.append('\\');
115                 outBuffer.append('r');
116                 continue;
117 
118             case '\f':
119                 outBuffer.append('\\');
120                 outBuffer.append('f');
121                 continue;
122 
123             default:
124                 if ((aChar < 20) || (aChar > 127))
125                 {
126                     outBuffer.append('\\');
127                     outBuffer.append('u');
128                     outBuffer.append(toHex((aChar >> 12) & 0xF));
129                     outBuffer.append(toHex((aChar >> 8) & 0xF));
130                     outBuffer.append(toHex((aChar >> 4) & 0xF));
131                     outBuffer.append(toHex((aChar >> 0) & 0xF));
132                 }
133                 else
134                 {
135                     if (specialSaveChars.indexOf(aChar) != -1)
136                         outBuffer.append('\\');
137 
138                     outBuffer.append(aChar);
139                 }
140             }
141         }
142 
143         return outBuffer.toString();
144     }
145 
146     /**
147      * Write a Properties to a Stream an leave the stream in tact
148      */
149     public static void load(Properties prop, InputStream in) throws IOException
150     {
151         BufferedReader bin = new BufferedReader(new InputStreamReader(in));
152         StringBuffer file = new StringBuffer();
153 
154         boolean alive = true;
155 
156         try
157         {
158             while (alive)
159             {
160                 String line = bin.readLine();
161 
162                 if (line == null || line.equals(DONE))
163                 {
164                     alive = false;
165                 }
166                 else
167                 {
168                     file.append(line);
169                     file.append(SEPARATOR);
170                 }
171             }
172         }
173         catch (Exception ex)
174         {
175             Reporter.informUser(PropertiesUtil.class, ex);
176         }
177 
178         InputStream ain = new ByteArrayInputStream(file.toString().getBytes());
179         loadInternal(ain, prop);
180     }
181 
182     /**
183      * Reads a property list (key and element pairs) from the input stream.
184      * @param in the input stream
185      * @exception IOException  if an error occurred when reading from the input stream.
186      */
187     private static void loadInternal(InputStream inStream, Properties prop) throws IOException
188     {
189         BufferedReader in = new BufferedReader(new InputStreamReader(inStream, "8859_1"));
190         while (true)
191         {
192             // Get next line
193             String line = in.readLine();
194             if (line == null)
195                 return;
196 
197             if (line.length() > 0)
198             {
199                 // Continue lines that end in slashes if they are not comments
200                 char firstChar = line.charAt(0);
201                 if ((firstChar != '#') && (firstChar != '!'))
202                 {
203                     while (continueLine(line))
204                     {
205                         String nextLine = in.readLine();
206                         if(nextLine == null)
207                             nextLine = new String("");
208 
209                         String loppedLine = line.substring(0, line.length()-1);
210 
211                         // Advance beyond whitespace on new line
212                         int startIndex=0;
213                         for(startIndex=0; startIndex<nextLine.length(); startIndex++)
214                             if (whiteSpaceChars.indexOf(nextLine.charAt(startIndex)) == -1)
215                                 break;
216                         nextLine = nextLine.substring(startIndex,nextLine.length());
217                         line = new String(loppedLine+nextLine);
218                     }
219 
220                     // Find start of key
221                     int len = line.length();
222                     int keyStart;
223                     for(keyStart=0; keyStart<len; keyStart++)
224                     {
225                         if (whiteSpaceChars.indexOf(line.charAt(keyStart)) == -1)
226                             break;
227                     }
228 
229                     // Find separation between key and value
230                     int separatorIndex;
231                     for(separatorIndex=keyStart; separatorIndex<len; separatorIndex++)
232                     {
233                         char currentChar = line.charAt(separatorIndex);
234                         if (currentChar == '\\')
235                             separatorIndex++;
236                         else if(keyValueSeparators.indexOf(currentChar) != -1)
237                             break;
238                     }
239 
240                     // Skip over whitespace after key if any
241                     int valueIndex;
242                     for (valueIndex=separatorIndex; valueIndex<len; valueIndex++)
243                         if (whiteSpaceChars.indexOf(line.charAt(valueIndex)) == -1)
244                             break;
245 
246                     // Skip over one non whitespace key value separators if any
247                     if (valueIndex < len)
248                         if (strictKeyValueSeparators.indexOf(line.charAt(valueIndex)) != -1)
249                             valueIndex++;
250 
251                     // Skip over white space after other separators if any
252                     while (valueIndex < len)
253                     {
254                         if (whiteSpaceChars.indexOf(line.charAt(valueIndex)) == -1)
255                             break;
256                         valueIndex++;
257                     }
258 
259                     String key = line.substring(keyStart, separatorIndex);
260                     String value = (separatorIndex < len) ? line.substring(valueIndex, len) : "";
261 
262                     // Convert then store key and value
263                     key = loadConvert(key);
264                     value = loadConvert(value);
265 
266                     prop.put(key, value);
267                 }
268             }
269         }
270     }
271 
272     /**
273      * Returns true if the given line is a line that must
274      * be appended to the next line
275      */
276     private static boolean continueLine(String line)
277     {
278         int slashCount = 0;
279         int index = line.length() - 1;
280         while((index >= 0) && (line.charAt(index--) == '\\'))
281             slashCount++;
282 
283         return (slashCount % 2 == 1);
284     }
285 
286     /**
287      * Converts encoded \\uxxxx to unicode chars
288      * and changes special saved chars to their original forms
289      */
290     private static String loadConvert(String theString)
291     {
292         char aChar;
293         int len = theString.length();
294         StringBuffer outBuffer = new StringBuffer(len);
295 
296         for (int x=0; x<len; )
297         {
298             aChar = theString.charAt(x++);
299             if (aChar == '\\')
300             {
301                 aChar = theString.charAt(x++);
302                 if (aChar == 'u')
303                 {
304                     // Read the xxxx
305                     int value=0;
306                     for (int i=0; i<4; i++)
307                     {
308                         aChar = theString.charAt(x++);
309                         switch (aChar)
310                         {
311                         case '0': case '1': case '2': case '3': case '4':
312                         case '5': case '6': case '7': case '8': case '9':
313                             value = (value << 4) + aChar - '0';
314                             break;
315 
316                         case 'a': case 'b': case 'c':
317                         case 'd': case 'e': case 'f':
318                             value = (value << 4) + 10 + aChar - 'a';
319                             break;
320 
321                         case 'A': case 'B': case 'C':
322                         case 'D': case 'E': case 'F':
323                             value = (value << 4) + 10 + aChar - 'A';
324                             break;
325 
326                         default:
327                             throw new IllegalArgumentException("Malformed \\uxxxx encoding.");
328                         }
329                     }
330 
331                     outBuffer.append((char)value);
332                 }
333                 else
334                 {
335                     if (aChar == 't') aChar = '\t';
336                     else if (aChar == 'r') aChar = '\r';
337                     else if (aChar == 'n') aChar = '\n';
338                     else if (aChar == 'f') aChar = '\f';
339 
340                     outBuffer.append(aChar);
341                 }
342             }
343             else
344             {
345                 outBuffer.append(aChar);
346             }
347         }
348         return outBuffer.toString();
349     }
350 
351     /**
352      * Convert a nibble to a hex character
353      * @param nibble the nibble to convert.
354      */
355     private static char toHex(int nibble)
356     {
357         return hexDigit[(nibble & 0xF)];
358     }
359 
360     /** A table of hex digits */
361     private static final char[] hexDigit =
362     {
363         '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
364     };
365 
366     /** Cache of line separator */
367     private static final String SEPARATOR = System.getProperty("line.separator");
368 
369     /** The end marker text */
370     private static final String DONE = "DONE";
371 
372     /* From Properties */
373     private static final String keyValueSeparators = "=: \t\r\n\f";
374     private static final String strictKeyValueSeparators = "=:";
375     private static final String specialSaveChars = "=: \t\r\n\f#!";
376     private static final String whiteSpaceChars = " \t\r\n\f";
377 }