001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.util;
011:
012: import java.io.ByteArrayInputStream;
013: import java.io.File;
014: import java.io.FileInputStream;
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.io.InputStreamReader;
018: import java.io.UnsupportedEncodingException;
019: import java.util.zip.ZipEntry;
020: import java.util.zip.ZipFile;
021: import org.eclipse.jdt.core.compiler.CharOperation;
022:
023: public class Util implements SuffixConstants {
024:
025: public interface Displayable {
026: String displayString(Object o);
027: }
028:
029: private static final int DEFAULT_READING_SIZE = 8192;
030: public final static String UTF_8 = "UTF-8"; //$NON-NLS-1$
031: public static final String LINE_SEPARATOR = System
032: .getProperty("line.separator"); //$NON-NLS-1$
033:
034: public static final String EMPTY_STRING = new String(
035: CharOperation.NO_CHAR);
036: public static final int[] EMPTY_INT_ARRAY = new int[0];
037:
038: /**
039: * Returns the given bytes as a char array using a given encoding (null means platform default).
040: */
041: public static char[] bytesToChar(byte[] bytes, String encoding)
042: throws IOException {
043:
044: return getInputStreamAsCharArray(
045: new ByteArrayInputStream(bytes), bytes.length, encoding);
046:
047: }
048:
049: /**
050: * Returns the contents of the given file as a byte array.
051: * @throws IOException if a problem occured reading the file.
052: */
053: public static byte[] getFileByteContent(File file)
054: throws IOException {
055: InputStream stream = null;
056: try {
057: stream = new FileInputStream(file);
058: return getInputStreamAsByteArray(stream, (int) file
059: .length());
060: } finally {
061: if (stream != null) {
062: try {
063: stream.close();
064: } catch (IOException e) {
065: // ignore
066: }
067: }
068: }
069: }
070:
071: /**
072: * Returns the contents of the given file as a char array.
073: * When encoding is null, then the platform default one is used
074: * @throws IOException if a problem occured reading the file.
075: */
076: public static char[] getFileCharContent(File file, String encoding)
077: throws IOException {
078: InputStream stream = null;
079: try {
080: stream = new FileInputStream(file);
081: return getInputStreamAsCharArray(stream, (int) file
082: .length(), encoding);
083: } finally {
084: if (stream != null) {
085: try {
086: stream.close();
087: } catch (IOException e) {
088: // ignore
089: }
090: }
091: }
092: }
093:
094: /*
095: * NIO support to get input stream as byte array.
096: * Not used as with JDK 1.4.2 this support is slower than standard IO one...
097: * Keep it as comment for future in case of next JDK versions improve performance
098: * in this area...
099: *
100: public static byte[] getInputStreamAsByteArray(FileInputStream stream, int length)
101: throws IOException {
102:
103: FileChannel channel = stream.getChannel();
104: int size = (int)channel.size();
105: if (length >= 0 && length < size) size = length;
106: byte[] contents = new byte[size];
107: ByteBuffer buffer = ByteBuffer.wrap(contents);
108: channel.read(buffer);
109: return contents;
110: }
111: */
112: /**
113: * Returns the given input stream's contents as a byte array.
114: * If a length is specified (ie. if length != -1), only length bytes
115: * are returned. Otherwise all bytes in the stream are returned.
116: * Note this doesn't close the stream.
117: * @throws IOException if a problem occured reading the stream.
118: */
119: public static byte[] getInputStreamAsByteArray(InputStream stream,
120: int length) throws IOException {
121: byte[] contents;
122: if (length == -1) {
123: contents = new byte[0];
124: int contentsLength = 0;
125: int amountRead = -1;
126: do {
127: int amountRequested = Math.max(stream.available(),
128: DEFAULT_READING_SIZE); // read at least 8K
129:
130: // resize contents if needed
131: if (contentsLength + amountRequested > contents.length) {
132: System.arraycopy(contents, 0,
133: contents = new byte[contentsLength
134: + amountRequested], 0,
135: contentsLength);
136: }
137:
138: // read as many bytes as possible
139: amountRead = stream.read(contents, contentsLength,
140: amountRequested);
141:
142: if (amountRead > 0) {
143: // remember length of contents
144: contentsLength += amountRead;
145: }
146: } while (amountRead != -1);
147:
148: // resize contents if necessary
149: if (contentsLength < contents.length) {
150: System.arraycopy(contents, 0,
151: contents = new byte[contentsLength], 0,
152: contentsLength);
153: }
154: } else {
155: contents = new byte[length];
156: int len = 0;
157: int readSize = 0;
158: while ((readSize != -1) && (len != length)) {
159: // See PR 1FMS89U
160: // We record first the read size. In this case len is the actual read size.
161: len += readSize;
162: readSize = stream.read(contents, len, length - len);
163: }
164: }
165:
166: return contents;
167: }
168:
169: /*
170: * NIO support to get input stream as char array.
171: * Not used as with JDK 1.4.2 this support is slower than standard IO one...
172: * Keep it as comment for future in case of next JDK versions improve performance
173: * in this area...
174: public static char[] getInputStreamAsCharArray(FileInputStream stream, int length, String encoding)
175: throws IOException {
176:
177: FileChannel channel = stream.getChannel();
178: int size = (int)channel.size();
179: if (length >= 0 && length < size) size = length;
180: Charset charset = encoding==null?systemCharset:Charset.forName(encoding);
181: if (charset != null) {
182: MappedByteBuffer bbuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
183: CharsetDecoder decoder = charset.newDecoder();
184: CharBuffer buffer = decoder.decode(bbuffer);
185: char[] contents = new char[buffer.limit()];
186: buffer.get(contents);
187: return contents;
188: }
189: throw new UnsupportedCharsetException(SYSTEM_FILE_ENCODING);
190: }
191: */
192: /**
193: * Returns the given input stream's contents as a character array.
194: * If a length is specified (ie. if length != -1), this represents the number of bytes in the stream.
195: * Note this doesn't close the stream.
196: * @throws IOException if a problem occured reading the stream.
197: */
198: public static char[] getInputStreamAsCharArray(InputStream stream,
199: int length, String encoding) throws IOException {
200: InputStreamReader reader = null;
201: try {
202: reader = encoding == null ? new InputStreamReader(stream)
203: : new InputStreamReader(stream, encoding);
204: } catch (UnsupportedEncodingException e) {
205: // encoding is not supported
206: reader = new InputStreamReader(stream);
207: }
208: char[] contents;
209: int totalRead = 0;
210: if (length == -1) {
211: contents = CharOperation.NO_CHAR;
212: } else {
213: // length is a good guess when the encoding produces less or the same amount of characters than the file length
214: contents = new char[length]; // best guess
215: }
216:
217: while (true) {
218: int amountRequested;
219: if (totalRead < length) {
220: // until known length is met, reuse same array sized eagerly
221: amountRequested = length - totalRead;
222: } else {
223: // reading beyond known length
224: int current = reader.read();
225: if (current < 0)
226: break;
227:
228: amountRequested = Math.max(stream.available(),
229: DEFAULT_READING_SIZE); // read at least 8K
230:
231: // resize contents if needed
232: if (totalRead + 1 + amountRequested > contents.length)
233: System.arraycopy(contents, 0,
234: contents = new char[totalRead + 1
235: + amountRequested], 0, totalRead);
236:
237: // add current character
238: contents[totalRead++] = (char) current; // coming from totalRead==length
239: }
240: // read as many chars as possible
241: int amountRead = reader.read(contents, totalRead,
242: amountRequested);
243: if (amountRead < 0)
244: break;
245: totalRead += amountRead;
246: }
247:
248: // Do not keep first character for UTF-8 BOM encoding
249: int start = 0;
250: if (totalRead > 0 && UTF_8.equals(encoding)) {
251: if (contents[0] == 0xFEFF) { // if BOM char then skip
252: totalRead--;
253: start = 1;
254: }
255: }
256:
257: // resize contents if necessary
258: if (totalRead < contents.length)
259: System.arraycopy(contents, start,
260: contents = new char[totalRead], 0, totalRead);
261:
262: return contents;
263: }
264:
265: public static int getLineNumber(int position, int[] lineEnds,
266: int g, int d) {
267: if (lineEnds == null)
268: return 1;
269: if (d == -1)
270: return 1;
271: int m = g, start;
272: while (g <= d) {
273: m = g + (d - g) / 2;
274: if (position < (start = lineEnds[m])) {
275: d = m - 1;
276: } else if (position > start) {
277: g = m + 1;
278: } else {
279: return m + 1;
280: }
281: }
282: if (position < lineEnds[m]) {
283: return m + 1;
284: }
285: return m + 2;
286: }
287:
288: /**
289: * Returns the contents of the given zip entry as a byte array.
290: * @throws IOException if a problem occured reading the zip entry.
291: */
292: public static byte[] getZipEntryByteContent(ZipEntry ze, ZipFile zip)
293: throws IOException {
294:
295: InputStream stream = null;
296: try {
297: stream = zip.getInputStream(ze);
298: if (stream == null)
299: throw new IOException(
300: "Invalid zip entry name : " + ze.getName()); //$NON-NLS-1$
301: return getInputStreamAsByteArray(stream, (int) ze.getSize());
302: } finally {
303: if (stream != null) {
304: try {
305: stream.close();
306: } catch (IOException e) {
307: // ignore
308: }
309: }
310: }
311: }
312:
313: /**
314: * Returns true iff str.toLowerCase().endsWith(".jar") || str.toLowerCase().endsWith(".zip")
315: * implementation is not creating extra strings.
316: */
317: public final static boolean isArchiveFileName(String name) {
318: int nameLength = name == null ? 0 : name.length();
319: int suffixLength = SUFFIX_JAR.length;
320: if (nameLength < suffixLength)
321: return false;
322:
323: // try to match as JAR file
324: for (int i = 0; i < suffixLength; i++) {
325: char c = name.charAt(nameLength - i - 1);
326: int suffixIndex = suffixLength - i - 1;
327: if (c != SUFFIX_jar[suffixIndex]
328: && c != SUFFIX_JAR[suffixIndex]) {
329:
330: // try to match as ZIP file
331: suffixLength = SUFFIX_ZIP.length;
332: if (nameLength < suffixLength)
333: return false;
334: for (int j = 0; j < suffixLength; j++) {
335: c = name.charAt(nameLength - j - 1);
336: suffixIndex = suffixLength - j - 1;
337: if (c != SUFFIX_zip[suffixIndex]
338: && c != SUFFIX_ZIP[suffixIndex])
339: return false;
340: }
341: return true;
342: }
343: }
344: return true;
345: }
346:
347: /**
348: * Returns true iff str.toLowerCase().endsWith(".class")
349: * implementation is not creating extra strings.
350: */
351: public final static boolean isClassFileName(char[] name) {
352: int nameLength = name == null ? 0 : name.length;
353: int suffixLength = SUFFIX_CLASS.length;
354: if (nameLength < suffixLength)
355: return false;
356:
357: for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
358: char c = name[offset + i];
359: if (c != SUFFIX_class[i] && c != SUFFIX_CLASS[i])
360: return false;
361: }
362: return true;
363: }
364:
365: /**
366: * Returns true iff str.toLowerCase().endsWith(".class")
367: * implementation is not creating extra strings.
368: */
369: public final static boolean isClassFileName(String name) {
370: int nameLength = name == null ? 0 : name.length();
371: int suffixLength = SUFFIX_CLASS.length;
372: if (nameLength < suffixLength)
373: return false;
374:
375: for (int i = 0; i < suffixLength; i++) {
376: char c = name.charAt(nameLength - i - 1);
377: int suffixIndex = suffixLength - i - 1;
378: if (c != SUFFIX_class[suffixIndex]
379: && c != SUFFIX_CLASS[suffixIndex])
380: return false;
381: }
382: return true;
383: }
384:
385: /* TODO (philippe) should consider promoting it to CharOperation
386: * Returns whether the given resource path matches one of the inclusion/exclusion
387: * patterns.
388: * NOTE: should not be asked directly using pkg root pathes
389: * @see IClasspathEntry#getInclusionPatterns
390: * @see IClasspathEntry#getExclusionPatterns
391: */
392: public final static boolean isExcluded(char[] path,
393: char[][] inclusionPatterns, char[][] exclusionPatterns,
394: boolean isFolderPath) {
395: if (inclusionPatterns == null && exclusionPatterns == null)
396: return false;
397:
398: inclusionCheck: if (inclusionPatterns != null) {
399: for (int i = 0, length = inclusionPatterns.length; i < length; i++) {
400: char[] pattern = inclusionPatterns[i];
401: char[] folderPattern = pattern;
402: if (isFolderPath) {
403: int lastSlash = CharOperation.lastIndexOf('/',
404: pattern);
405: if (lastSlash != -1
406: && lastSlash != pattern.length - 1) { // trailing slash -> adds '**' for free (see http://ant.apache.org/manual/dirtasks.html)
407: int star = CharOperation.indexOf('*', pattern,
408: lastSlash);
409: if ((star == -1 || star >= pattern.length - 1 || pattern[star + 1] != '*')) {
410: folderPattern = CharOperation.subarray(
411: pattern, 0, lastSlash);
412: }
413: }
414: }
415: if (CharOperation.pathMatch(folderPattern, path, true,
416: '/')) {
417: break inclusionCheck;
418: }
419: }
420: return true; // never included
421: }
422: if (isFolderPath) {
423: path = CharOperation.concat(path, new char[] { '*' }, '/');
424: }
425: if (exclusionPatterns != null) {
426: for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
427: if (CharOperation.pathMatch(exclusionPatterns[i], path,
428: true, '/')) {
429: return true;
430: }
431: }
432: }
433: return false;
434: }
435:
436: /**
437: * Returns true iff str.toLowerCase().endsWith(".java")
438: * implementation is not creating extra strings.
439: */
440: public final static boolean isJavaFileName(char[] name) {
441: int nameLength = name == null ? 0 : name.length;
442: int suffixLength = SUFFIX_JAVA.length;
443: if (nameLength < suffixLength)
444: return false;
445:
446: for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
447: char c = name[offset + i];
448: if (c != SUFFIX_java[i] && c != SUFFIX_JAVA[i])
449: return false;
450: }
451: return true;
452: }
453:
454: /**
455: * Returns true iff str.toLowerCase().endsWith(".java")
456: * implementation is not creating extra strings.
457: */
458: public final static boolean isJavaFileName(String name) {
459: int nameLength = name == null ? 0 : name.length();
460: int suffixLength = SUFFIX_JAVA.length;
461: if (nameLength < suffixLength)
462: return false;
463:
464: for (int i = 0; i < suffixLength; i++) {
465: char c = name.charAt(nameLength - i - 1);
466: int suffixIndex = suffixLength - i - 1;
467: if (c != SUFFIX_java[suffixIndex]
468: && c != SUFFIX_JAVA[suffixIndex])
469: return false;
470: }
471: return true;
472: }
473:
474: public static void reverseQuickSort(char[][] list, int left,
475: int right, int[] result) {
476: int original_left = left;
477: int original_right = right;
478: char[] mid = list[(right + left) / 2];
479: do {
480: while (CharOperation.compareTo(list[left], mid) > 0) {
481: left++;
482: }
483: while (CharOperation.compareTo(mid, list[right]) > 0) {
484: right--;
485: }
486: if (left <= right) {
487: char[] tmp = list[left];
488: list[left] = list[right];
489: list[right] = tmp;
490: int temp = result[left];
491: result[left] = result[right];
492: result[right] = temp;
493: left++;
494: right--;
495: }
496: } while (left <= right);
497: if (original_left < right) {
498: reverseQuickSort(list, original_left, right, result);
499: }
500: if (left < original_right) {
501: reverseQuickSort(list, left, original_right, result);
502: }
503: }
504:
505: public static void reverseQuickSort(char[][] list, int left,
506: int right) {
507: int original_left = left;
508: int original_right = right;
509: char[] mid = list[(right + left) / 2];
510: do {
511: while (CharOperation.compareTo(list[left], mid) > 0) {
512: left++;
513: }
514: while (CharOperation.compareTo(mid, list[right]) > 0) {
515: right--;
516: }
517: if (left <= right) {
518: char[] tmp = list[left];
519: list[left] = list[right];
520: list[right] = tmp;
521: left++;
522: right--;
523: }
524: } while (left <= right);
525: if (original_left < right) {
526: reverseQuickSort(list, original_left, right);
527: }
528: if (left < original_right) {
529: reverseQuickSort(list, left, original_right);
530: }
531: }
532:
533: /**
534: * INTERNAL USE-ONLY
535: * Search the column number corresponding to a specific position
536: */
537: public static final int searchColumnNumber(int[] startLineIndexes,
538: int lineNumber, int position) {
539: switch (lineNumber) {
540: case 1:
541: return position + 1;
542: case 2:
543: return position - startLineIndexes[0];
544: default:
545: int line = lineNumber - 2;
546: int length = startLineIndexes.length;
547: if (line >= length) {
548: return position - startLineIndexes[length - 1];
549: }
550: return position - startLineIndexes[line];
551: }
552: }
553:
554: /**
555: * Converts a boolean value into Boolean.
556: * @param bool The boolean to convert
557: * @return The corresponding Boolean object (TRUE or FALSE).
558: */
559: public static Boolean toBoolean(boolean bool) {
560: if (bool) {
561: return Boolean.TRUE;
562: } else {
563: return Boolean.FALSE;
564: }
565: }
566:
567: /**
568: * Converts an array of Objects into String.
569: */
570: public static String toString(Object[] objects) {
571: return toString(objects, new Displayable() {
572: public String displayString(Object o) {
573: if (o == null)
574: return "null"; //$NON-NLS-1$
575: return o.toString();
576: }
577: });
578: }
579:
580: /**
581: * Converts an array of Objects into String.
582: */
583: public static String toString(Object[] objects, Displayable renderer) {
584: if (objects == null)
585: return ""; //$NON-NLS-1$
586: StringBuffer buffer = new StringBuffer(10);
587: for (int i = 0; i < objects.length; i++) {
588: if (i > 0)
589: buffer.append(", "); //$NON-NLS-1$
590: buffer.append(renderer.displayString(objects[i]));
591: }
592: return buffer.toString();
593: }
594: }
|