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