001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.openide.filesystems;
042:
043: import java.io.IOException;
044: import java.io.File;
045: import java.io.FileInputStream;
046: import java.io.FileOutputStream;
047: import java.io.InputStream;
048: import java.io.PrintStream;
049: import java.io.InputStreamReader;
050: import java.io.BufferedReader;
051: import java.io.DataOutput;
052: import java.io.DataInput;
053: import java.util.HashMap;
054: import java.util.List;
055: import java.util.ArrayList;
056:
057: /**
058: * A set of utility methods.
059: */
060: public abstract class Utilities {
061:
062: /** Counts padding size from given size, i.e. 1 for less than 10, 3 for 100 - 999, etc. */
063: public static int expPaddingSize(int size) {
064: int ret = 0;
065:
066: while (size > 0) {
067: size /= 10;
068: ret++;
069: }
070: return ret;
071: }
072:
073: /** Appends paddingSize number of digits e.g. 00digit */
074: public static void appendNDigits(int digit, int paddingSize,
075: StringBuffer buffer) {
076: int localLength = paddingSize - 1;
077: int exp[] = new int[] { 0, 10, 100, 1000, 10000, 100000,
078: 1000000 };
079:
080: while (digit < exp[localLength--]) {
081: buffer.append('0');
082: }
083:
084: buffer.append(String.valueOf(digit));
085: }
086:
087: /** Creates jar file
088: * @param srcdir which folder to be zipped
089: * @param <tt>name</tt> name of the jar
090: */
091: public static File createJar(File srcdir, String name)
092: throws Exception {
093: Process proc = Runtime.getRuntime().exec(
094: "jar cf " + name + " .", null, srcdir);
095: proc.waitFor();
096: copyIS(proc.getErrorStream(), System.out);
097:
098: return new File(srcdir, name);
099: }
100:
101: /** Copy content of a stream to a PrintStream */
102: public static void copyIS(InputStream is, PrintStream out)
103: throws Exception {
104: BufferedReader reader = new BufferedReader(
105: new InputStreamReader(is));
106: String str;
107: while ((str = reader.readLine()) != null) {
108: out.println(str);
109: }
110: }
111:
112: /** Writes a file to DataOutput */
113: public static void writeFile(File src, DataOutput dest)
114: throws IOException {
115: FileInputStream fis = new FileInputStream(src);
116: long len = src.length();
117: dest.writeUTF(src.getName());
118: dest.writeLong(len);
119:
120: byte[] buffer = new byte[5000];
121: int read;
122: for (;;) {
123: read = fis.read(buffer);
124: if (read < 0) {
125: break;
126: }
127: dest.write(buffer, 0, read);
128: }
129:
130: fis.close();
131: }
132:
133: /** Reads a file from DataInput */
134: public static File readFile(File dest, DataInput src)
135: throws IOException {
136: File ret = new File(dest, src.readUTF());
137: FileOutputStream fos = new FileOutputStream(ret);
138: long len = src.readLong();
139: final int BUF_SIZE = 5000;
140: byte[] buffer = new byte[BUF_SIZE];
141:
142: int read;
143: int shouldRead;
144: for (;;) {
145: read = (int) Math.min(BUF_SIZE, len);
146: src.readFully(buffer, 0, read);
147: fos.write(buffer, 0, read);
148: len -= read;
149: if (len <= 0) {
150: break;
151: }
152: }
153:
154: fos.close();
155: return ret;
156: }
157:
158: /**
159: * Simple grep
160: */
161: public static final class Matcher {
162: private State first;
163:
164: /** new Matcher */
165: public Matcher(String[] patterns) {
166: first = new State(null);
167: initStates(patterns);
168: }
169:
170: /** Inits this Matcher */
171: private void initStates(String[] patterns) {
172: List groups = createGroups(patterns, 0);
173: StringGroup.resolveGroups(groups);
174: StringGroup.fillState(first, groups);
175: createDG(first);
176: }
177:
178: /** Creates directed graph of States */
179: private static void createDG(State state) {
180: Transition[] ts = state.getTransitions();
181: for (int i = 0; i < ts.length; i++) {
182: createDG(ts[i].getState(), ts);
183: }
184: }
185:
186: /** Creates directed cycled graph of States*/
187: private static void createDG(State state, Transition[] ts) {
188: Transition[] myts = state.getTransitions();
189:
190: for (int j = 0; j < myts.length; j++) {
191: createDG(myts[j].getState(), ts);
192: }
193:
194: mergeTransitions(state, ts);
195: }
196:
197: /** Creates cycles in a graph of States
198: * Adds given Transitions to given state.
199: */
200: private static void mergeTransitions(State state,
201: Transition[] ts) {
202: for (int i = 0; i < ts.length; i++) {
203: State istate = ts[i].getState();
204: if (istate == state) {
205: continue;
206: }
207:
208: if (state.isDefined(ts[i].getChar())) {
209: State tmp = state.getNext(ts[i].getChar());
210: if (tmp != istate) {
211: makePtr(tmp, istate);
212: }
213: } else {
214: state.addTransition(ts[i]);
215: }
216: }
217: }
218:
219: /** Links one state to another state */
220: private static void makePtr(State from, State to) {
221: Transition[] tots = to.getTransitions();
222: mergeTransitions(from, tots);
223:
224: if (to.isTerminal()) {
225: String[] matches = to.getMatches();
226: from.markAsTerminal(matches[0]);
227: for (int i = 1; i < matches.length; i++) {
228: from.addMatch(matches[i]);
229: }
230: }
231: }
232:
233: /** Creates groups for patterns */
234: static List createGroups(String[] patterns, int level) {
235: HashMap map = new HashMap();
236:
237: for (int i = 0; i < patterns.length; i++) {
238: Character divider = new Character(patterns[i]
239: .charAt(level));
240: StringGroup grp = (StringGroup) map.get(divider);
241: if (grp == null) {
242: grp = new StringGroup(level);
243: map.put(divider, grp);
244: }
245: grp.addString(patterns[i]);
246: }
247:
248: return new ArrayList(map.values());
249: }
250:
251: /** @return initial state for this Matcher */
252: public State getInitState() {
253: return first;
254: }
255:
256: /** Encapsulates a group of strings with a common prefix */
257: static final class StringGroup {
258: private List strings;
259: private final int startIndex;
260: private List subGroups;
261: private int minIdx;
262: private int endIndex;
263: private boolean terminal;
264:
265: /** New group */
266: public StringGroup(int idx) {
267: this .startIndex = idx;
268: minIdx = Integer.MAX_VALUE;
269: strings = new ArrayList();
270: this .terminal = false;
271: }
272:
273: /** Adds a String to this group */
274: public void addString(String s) {
275: strings.add(s);
276: minIdx = Math.min(minIdx, s.length());
277: }
278:
279: /** @return true if this group contains only one String */
280: private boolean isTerminal() {
281: if (strings.size() <= 1 || terminal) {
282: return true;
283: } else {
284: return false;
285: }
286: }
287:
288: private boolean hasSubGroups() {
289: return (subGroups != null) && (subGroups.size() > 0);
290: }
291:
292: /** @return first char for this group */
293: private char getFirstChar() {
294: return ((String) strings.get(0)).charAt(startIndex);
295: }
296:
297: /** Resolves this group and all its sub groups */
298: private void resolve() {
299: if (isTerminal()) {
300: endIndex = minIdx;
301: return;
302: }
303:
304: subGroups = new ArrayList();
305: int i = startIndex + 1;
306: out: for (; i < minIdx; i++) {
307: char c = ((String) strings.get(0)).charAt(i);
308:
309: for (int j = 1; j < strings.size(); j++) {
310: char c2 = ((String) strings.get(j)).charAt(i);
311: if (c2 != c) {
312: String[] arr = (String[]) strings
313: .toArray(new String[strings.size()]);
314: subGroups = createGroups(arr, endIndex = i);
315: break out;
316: }
317: }
318: }
319:
320: if (i == minIdx) {
321: endIndex = minIdx;
322: List longStrings = new ArrayList();
323: for (int j = 0; j < strings.size(); j++) {
324: String str = (String) strings.get(j);
325: if (str.length() > minIdx) {
326: longStrings.add(str);
327: }
328: }
329:
330: String[] arr = (String[]) longStrings
331: .toArray(new String[longStrings.size()]);
332: subGroups = createGroups(arr, minIdx);
333: terminal = true;
334: }
335:
336: resolveGroups(subGroups);
337: }
338:
339: /** @return a String that */
340: private String getShortOrAny() {
341: for (int j = 0; j < strings.size(); j++) {
342: String str = (String) strings.get(j);
343: if (str.length() == minIdx) {
344: return str;
345: }
346: }
347:
348: return (String) strings.get(0);
349: }
350:
351: /** @return initial State for this group */
352: private State createEntryState(State firstState) {
353: State entry = new State(firstState);
354: String any = getShortOrAny();
355: State iter = entry;
356:
357: for (int i = startIndex + 1; i < endIndex; i++) {
358: char c = any.charAt(i);
359: State state = new State(firstState);
360: Transition t = new Transition(c, state);
361: iter.addTransition(t);
362: iter = state;
363: }
364:
365: if (isTerminal()) {
366: iter.markAsTerminal(any);
367: }
368:
369: if (hasSubGroups()) {
370: fillState(iter, firstState, subGroups);
371: }
372:
373: return entry;
374: }
375:
376: /** Joins given groups to state with a given firstState */
377: public static void fillState(State state, List groups) {
378: fillState(state, state, groups);
379: }
380:
381: /** Joins given groups to state with a given firstState */
382: private static void fillState(State state,
383: State firstState, List groups) {
384: Transition[] tmp = new Transition[1];
385: for (int i = 0; i < groups.size(); i++) {
386: StringGroup grp = (StringGroup) groups.get(i);
387: State xstate = grp.createEntryState(firstState);
388: tmp[0] = new Transition(grp.getFirstChar(), xstate);
389: mergeTransitions(state, tmp);
390: }
391: }
392:
393: /** Resolves all groups */
394: static void resolveGroups(List groups) {
395: int len = groups.size();
396:
397: for (int i = 0; i < len; i++) {
398: StringGroup grp = (StringGroup) groups.get(i);
399: grp.resolve();
400: }
401: }
402: }
403:
404: /** Represents state of the automata */
405: public static final class State {
406: private HashMap transitions;
407: private State first;
408: private boolean terminal;
409: private List matches;
410:
411: /** New State */
412: public State(State first) {
413: this .transitions = new HashMap();
414: this .matches = new ArrayList();
415: this .terminal = false;
416: if (first == null) {
417: this .first = this ;
418: } else {
419: this .first = first;
420: }
421: }
422:
423: /** Adds on Transition */
424: void addTransition(Transition t) {
425: transitions.put(t.getHashKey(), t);
426: }
427:
428: /** @return next State for the given char */
429: public State getNext(char c) {
430: Transition t = (Transition) transitions
431: .get(new Character(c));
432: if (t != null) {
433: return t.getState();
434: } else {
435: return first;
436: }
437: }
438:
439: /** @return true iff there exists a Transition for given char */
440: boolean isDefined(char c) {
441: return (transitions.get(new Character(c)) != null);
442: }
443:
444: /** This is a match */
445: void markAsTerminal(String match) {
446: terminal = true;
447: addMatch(match);
448: }
449:
450: /** Adds this String to its matches */
451: void addMatch(String match) {
452: matches.add(match);
453: }
454:
455: /** @return matches */
456: public String[] getMatches() {
457: return (String[]) matches.toArray(new String[matches
458: .size()]);
459: }
460:
461: /** @return true iff it is a match */
462: public boolean isTerminal() {
463: return terminal;
464: }
465:
466: /** @return all transitions for this State */
467: Transition[] getTransitions() {
468: return (Transition[]) transitions.values().toArray(
469: new Transition[transitions.size()]);
470: }
471: }
472:
473: /** Bound to State - represents mapping of a char to next State */
474: static final class Transition {
475: private char c;
476: private State nextState;
477:
478: /** New Transition */
479: public Transition(char c, State nextState) {
480: this .c = c;
481: this .nextState = nextState;
482: }
483:
484: /** Hash key for this Transition */
485: public Object getHashKey() {
486: return new Character(c);
487: }
488:
489: /** @return char */
490: public char getChar() {
491: return c;
492: }
493:
494: /** @return State for this Transition */
495: public State getState() {
496: return nextState;
497: }
498: }
499: }
500:
501: }
|