8739ba6a2e7b0d67ad6c5f903e2ae504d8e17f0a
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / util / Util.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.util;
12
13 import java.io.BufferedInputStream;
14 import java.io.ByteArrayInputStream;
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.InputStreamReader;
20 import java.util.Locale;
21 import java.util.MissingResourceException;
22 import java.util.ResourceBundle;
23 import java.util.zip.ZipEntry;
24 import java.util.zip.ZipFile;
25
26 import net.sourceforge.phpdt.core.compiler.CharOperation;
27 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
28
29 public class Util {
30
31         public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
32         public static char[] LINE_SEPARATOR_CHARS = LINE_SEPARATOR.toCharArray();
33         public final static char[] SUFFIX_class = ".class".toCharArray(); //$NON-NLS-1$
34         public final static char[] SUFFIX_CLASS = ".CLASS".toCharArray(); //$NON-NLS-1$
35         public final static char[] SUFFIX_java = ".java".toCharArray(); //$NON-NLS-1$
36         public final static char[] SUFFIX_JAVA = ".JAVA".toCharArray(); //$NON-NLS-1$
37         public final static char[] SUFFIX_jar = ".jar".toCharArray(); //$NON-NLS-1$
38         public final static char[] SUFFIX_JAR = ".JAR".toCharArray(); //$NON-NLS-1$
39         public final static char[] SUFFIX_zip = ".zip".toCharArray(); //$NON-NLS-1$
40         public final static char[] SUFFIX_ZIP = ".ZIP".toCharArray(); //$NON-NLS-1$
41                 
42         private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
43         private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
44         private static final int DEFAULT_READING_SIZE = 8192;
45         
46         /* Bundle containing messages */
47         protected static ResourceBundle bundle;
48         private final static String bundleName =
49                 "net.sourceforge.phpdt.internal.compiler.util.messages"; //$NON-NLS-1$
50         static {
51                 relocalize();
52         }
53         /**
54          * Lookup the message with the given ID in this catalog and bind its
55          * substitution locations with the given strings.
56          */
57         public static String bind(String id, String binding1, String binding2) {
58                 return bind(id, new String[] { binding1, binding2 });
59         }
60         /**
61          * Lookup the message with the given ID in this catalog and bind its
62          * substitution locations with the given string.
63          */
64         public static String bind(String id, String binding) {
65                 return bind(id, new String[] { binding });
66         }
67         /**
68          * Lookup the message with the given ID in this catalog and bind its
69          * substitution locations with the given string values.
70          */
71         public static String bind(String id, String[] bindings) {
72                 if (id == null)
73                         return "No message available"; //$NON-NLS-1$
74                 String message = null;
75                 try {
76                         message = bundle.getString(id);
77                 } catch (MissingResourceException e) {
78                         // If we got an exception looking for the message, fail gracefully by just returning
79                         // the id we were looking for.  In most cases this is semi-informative so is not too bad.
80                         return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
81                 }
82                 // for compatibility with MessageFormat which eliminates double quotes in original message
83                 char[] messageWithNoDoubleQuotes =
84                         CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
85                 message = new String(messageWithNoDoubleQuotes);
86
87                 if (bindings == null)
88                         return message;
89
90                 int length = message.length();
91                 int start = -1;
92                 int end = length;
93                 StringBuffer output = new StringBuffer(80);
94                 while (true) {
95                         if ((end = message.indexOf('{', start)) > -1) {
96                                 output.append(message.substring(start + 1, end));
97                                 if ((start = message.indexOf('}', end)) > -1) {
98                                         int index = -1;
99                                         try {
100                                                 index = Integer.parseInt(message.substring(end + 1, start));
101                                                 output.append(bindings[index]);
102                                         } catch (NumberFormatException nfe) {
103                                                 output.append(message.substring(end + 1, start + 1));
104                                         } catch (ArrayIndexOutOfBoundsException e) {
105                                                 output.append("{missing " + Integer.toString(index) + "}");     //$NON-NLS-2$ //$NON-NLS-1$
106                                         }
107                                 } else {
108                                         output.append(message.substring(end, length));
109                                         break;
110                                 }
111                         } else {
112                                 output.append(message.substring(start + 1, length));
113                                 break;
114                         }
115                 }
116                 return output.toString();
117         }
118         /**
119          * Lookup the message with the given ID in this catalog 
120          */
121         public static String bind(String id) {
122                 return bind(id, (String[]) null);
123         }
124         /**
125          * Creates a NLS catalog for the given locale.
126          */
127         public static void relocalize() {
128                 try {
129                         bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
130                 } catch(MissingResourceException e) {
131                         System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
132                         throw e;
133                 }
134         }
135         /**
136          * Returns the given bytes as a char array using a given encoding (null means platform default).
137          */
138         public static char[] bytesToChar(byte[] bytes, String encoding) throws IOException {
139
140                 return getInputStreamAsCharArray(new ByteArrayInputStream(bytes), bytes.length, encoding);
141
142         }
143         /**
144          * Returns the contents of the given file as a byte array.
145          * @throws IOException if a problem occured reading the file.
146          */
147         public static byte[] getFileByteContent(File file) throws IOException {
148                 InputStream stream = null;
149                 try {
150                         stream = new BufferedInputStream(new FileInputStream(file));
151                         return getInputStreamAsByteArray(stream, (int) file.length());
152                 } finally {
153                         if (stream != null) {
154                                 try {
155                                         stream.close();
156                                 } catch (IOException e) {
157                                 }
158                         }
159                 }
160         }
161         /**
162          * Returns the contents of the given file as a char array.
163          * When encoding is null, then the platform default one is used
164          * @throws IOException if a problem occured reading the file.
165          */
166         public static char[] getFileCharContent(File file, String encoding) throws IOException {
167                 InputStream stream = null;
168                 try {
169                         stream = new BufferedInputStream(new FileInputStream(file));
170                         return Util.getInputStreamAsCharArray(stream, (int) file.length(), encoding);
171                 } finally {
172                         if (stream != null) {
173                                 try {
174                                         stream.close();
175                                 } catch (IOException e) {
176                                 }
177                         }
178                 }
179         }
180         /**
181          * Returns the given input stream's contents as a byte array.
182          * If a length is specified (ie. if length != -1), only length bytes
183          * are returned. Otherwise all bytes in the stream are returned.
184          * Note this doesn't close the stream.
185          * @throws IOException if a problem occured reading the stream.
186          */
187         public static byte[] getInputStreamAsByteArray(InputStream stream, int length)
188                 throws IOException {
189                 byte[] contents;
190                 if (length == -1) {
191                         contents = new byte[0];
192                         int contentsLength = 0;
193                         int amountRead = -1;
194                         do {
195                                 int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE);  // read at least 8K
196                                 
197                                 // resize contents if needed
198                                 if (contentsLength + amountRequested > contents.length) {
199                                         System.arraycopy(
200                                                 contents,
201                                                 0,
202                                                 contents = new byte[contentsLength + amountRequested],
203                                                 0,
204                                                 contentsLength);
205                                 }
206
207                                 // read as many bytes as possible
208                                 amountRead = stream.read(contents, contentsLength, amountRequested);
209
210                                 if (amountRead > 0) {
211                                         // remember length of contents
212                                         contentsLength += amountRead;
213                                 }
214                         } while (amountRead != -1); 
215
216                         // resize contents if necessary
217                         if (contentsLength < contents.length) {
218                                 System.arraycopy(
219                                         contents,
220                                         0,
221                                         contents = new byte[contentsLength],
222                                         0,
223                                         contentsLength);
224                         }
225                 } else {
226                         contents = new byte[length];
227                         int len = 0;
228                         int readSize = 0;
229                         while ((readSize != -1) && (len != length)) {
230                                 // See PR 1FMS89U
231                                 // We record first the read size. In this case len is the actual read size.
232                                 len += readSize;
233                                 readSize = stream.read(contents, len, length - len);
234                         }
235                 }
236
237                 return contents;
238         }
239         /**
240          * Returns the given input stream's contents as a character array.
241          * If a length is specified (ie. if length != -1), only length chars
242          * are returned. Otherwise all chars in the stream are returned.
243          * Note this doesn't close the stream.
244          * @throws IOException if a problem occured reading the stream.
245          */
246         public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding)
247                 throws IOException {
248                 InputStreamReader reader = null;
249                 reader = encoding == null
250                                         ? new InputStreamReader(stream)
251                                         : new InputStreamReader(stream, encoding);
252                 char[] contents;
253                 if (length == -1) {
254                         contents = CharOperation.NO_CHAR;
255                         int contentsLength = 0;
256                         int amountRead = -1;
257                         do {
258                                 int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE);  // read at least 8K
259
260                                 // resize contents if needed
261                                 if (contentsLength + amountRequested > contents.length) {
262                                         System.arraycopy(
263                                                 contents,
264                                                 0,
265                                                 contents = new char[contentsLength + amountRequested],
266                                                 0,
267                                                 contentsLength);
268                                 }
269
270                                 // read as many chars as possible
271                                 amountRead = reader.read(contents, contentsLength, amountRequested);
272
273                                 if (amountRead > 0) {
274                                         // remember length of contents
275                                         contentsLength += amountRead;
276                                 }
277                         } while (amountRead != -1);
278
279                         // resize contents if necessary
280                         if (contentsLength < contents.length) {
281                                 System.arraycopy(
282                                         contents,
283                                         0,
284                                         contents = new char[contentsLength],
285                                         0,
286                                         contentsLength);
287                         }
288                 } else {
289                         contents = new char[length];
290                         int len = 0;
291                         int readSize = 0;
292                         while ((readSize != -1) && (len != length)) {
293                                 // See PR 1FMS89U
294                                 // We record first the read size. In this case len is the actual read size.
295                                 len += readSize;
296                                 readSize = reader.read(contents, len, length - len);
297                         }
298                         // See PR 1FMS89U
299                         // Now we need to resize in case the default encoding used more than one byte for each
300                         // character
301                         if (len != length)
302                                 System.arraycopy(contents, 0, (contents = new char[len]), 0, len);
303                 }
304
305                 return contents;
306         }
307         
308         /**
309          * Returns the contents of the given zip entry as a byte array.
310          * @throws IOException if a problem occured reading the zip entry.
311          */
312         public static byte[] getZipEntryByteContent(ZipEntry ze, ZipFile zip)
313                 throws IOException {
314
315                 InputStream stream = null;
316                 try {
317                         stream = new BufferedInputStream(zip.getInputStream(ze));
318                         return getInputStreamAsByteArray(stream, (int) ze.getSize());
319                 } finally {
320                         if (stream != null) {
321                                 try {
322                                         stream.close();
323                                 } catch (IOException e) {
324                                 }
325                         }
326                 }
327         }
328         /**
329          * Returns true iff str.toLowerCase().endsWith(".jar") || str.toLowerCase().endsWith(".zip")
330          * implementation is not creating extra strings.
331          */
332         public final static boolean isArchiveFileName(String name) {
333                 int nameLength = name == null ? 0 : name.length();
334                 int suffixLength = SUFFIX_JAR.length;
335                 if (nameLength < suffixLength) return false;
336
337                 // try to match as JAR file
338                 for (int i = 0; i < suffixLength; i++) {
339                         char c = name.charAt(nameLength - i - 1);
340                         int suffixIndex = suffixLength - i - 1;
341                         if (c != SUFFIX_jar[suffixIndex] && c != SUFFIX_JAR[suffixIndex]) {
342
343                                 // try to match as ZIP file
344                                 suffixLength = SUFFIX_ZIP.length;
345                                 if (nameLength < suffixLength) return false;
346                                 for (int j = 0; j < suffixLength; j++) {
347                                         c = name.charAt(nameLength - j - 1);
348                                         suffixIndex = suffixLength - j - 1;
349                                         if (c != SUFFIX_zip[suffixIndex] && c != SUFFIX_ZIP[suffixIndex]) return false;
350                                 }
351                                 return true;
352                         }
353                 }
354                 return true;            
355         }       
356         /**
357          * Returns true iff str.toLowerCase().endsWith(".class")
358          * implementation is not creating extra strings.
359          */
360         public final static boolean isClassFileName(String name) {
361                 int nameLength = name == null ? 0 : name.length();
362                 int suffixLength = SUFFIX_CLASS.length;
363                 if (nameLength < suffixLength) return false;
364
365                 for (int i = 0; i < suffixLength; i++) {
366                         char c = name.charAt(nameLength - i - 1);
367                         int suffixIndex = suffixLength - i - 1;
368                         if (c != SUFFIX_class[suffixIndex] && c != SUFFIX_CLASS[suffixIndex]) return false;
369                 }
370                 return true;            
371         }       
372         
373         /**
374          * Returns true iff str.toLowerCase().endsWith(".java")
375          * implementation is not creating extra strings.
376          */
377         public final static boolean isJavaFileName(String name) {
378                 return PHPFileUtil.isPHPFileName(name);
379 //              int nameLength = name == null ? 0 : name.length();
380 //              int suffixLength = SUFFIX_JAVA.length;
381 //              if (nameLength < suffixLength) return false;
382 //
383 //              for (int i = 0; i < suffixLength; i++) {
384 //                      char c = name.charAt(nameLength - i - 1);
385 //                      int suffixIndex = suffixLength - i - 1;
386 //                      if (c != SUFFIX_java[suffixIndex] && c != SUFFIX_JAVA[suffixIndex]) return false;
387 //              }
388 //              return true;            
389         }
390 }