misc
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / builder / IdentifierIndexManager.java
1 package net.sourceforge.phpeclipse.builder;
2
3 import java.io.BufferedInputStream;
4 import java.io.BufferedReader;
5 import java.io.FileNotFoundException;
6 import java.io.FileReader;
7 import java.io.FileWriter;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.Comparator;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.SortedMap;
18 import java.util.StringTokenizer;
19 import java.util.TreeMap;
20
21 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
22 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
23 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
24 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
25 import net.sourceforge.phpdt.internal.compiler.util.Util;
26 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
27 import net.sourceforge.phpeclipse.obfuscator.PHPIdentifier;
28
29 import org.eclipse.core.resources.IFile;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IStatus;
32
33 /**
34  * Manages the identifer index information for a specific project
35  *  
36  */
37 public class IdentifierIndexManager {
38   public class LineCreator implements ITerminalSymbols {
39     private Scanner fScanner;
40
41     private int fToken;
42
43     public LineCreator() {
44       fScanner = new Scanner(true, false, false, false, true, null, null);
45     }
46
47     /**
48      * Add the information of the current identifier to the line
49      * 
50      * @param typeOfIdentifier
51      *          the type of the identifier ('c'lass, 'd'efine, 'f'unction, 'm'ethod(class), 'v'ariable(class) 'g'lobal variable)
52      * @param identifier
53      *          current identifier
54      * @param line
55      *          Buffer for the current index line
56      * @param phpdocOffset
57      *          the offset of the PHPdoc comment if available
58      * @param phpdocLength
59      *          the length of the PHPdoc comment if available
60      */
61     private void addIdentifierInformation(char typeOfIdentifier, char[] identifier, StringBuffer line, int phpdocOffset,
62         int phpdocLength) {
63       line.append('\t');
64       line.append(typeOfIdentifier);
65       line.append(identifier);
66       line.append("\to"); // Offset
67       line.append(fScanner.getCurrentTokenStartPosition());
68       if (phpdocOffset >= 0) {
69         line.append("\tp"); // phpdoc offset
70         line.append(phpdocOffset);
71         line.append("\tl"); // phpdoc length
72         line.append(phpdocLength);
73       }
74     }
75
76     private void addClassVariableInformation(char typeOfIdentifier, char[] identifier, StringBuffer line, int phpdocOffset,
77         int phpdocLength) {
78       line.append('\t');
79       line.append(typeOfIdentifier);
80       line.append(identifier);
81       line.append("\to"); // Offset
82       // we don't store the '$' in the index for class variables:
83       line.append(fScanner.getCurrentTokenStartPosition() + 1);
84       if (phpdocOffset >= 0) {
85         line.append("\tp"); // phpdoc offset
86         line.append(phpdocOffset);
87         line.append("\tl"); // phpdoc length
88         line.append(phpdocLength);
89       }
90     }
91
92     /**
93      * Get the next token from input
94      */
95     private void getNextToken() {
96       try {
97         fToken = fScanner.getNextToken();
98         if (Scanner.DEBUG) {
99           int currentEndPosition = fScanner.getCurrentTokenEndPosition();
100           int currentStartPosition = fScanner.getCurrentTokenStartPosition();
101           System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
102           System.out.println(fScanner.toStringAction(fToken));
103         }
104         return;
105       } catch (InvalidInputException e) {
106         // ignore errors
107         //        e.printStackTrace();
108       }
109       fToken = TokenNameERROR;
110     }
111
112     private void parseDeclarations(char[] parent, StringBuffer buf, boolean goBack) {
113       char[] ident;
114       char[] classVariable;
115       int counter = 0;
116       boolean hasModifiers = false;
117       int phpdocOffset = -1;
118       int phpdocLength = -1;
119       try {
120         while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
121           phpdocOffset = -1;
122           hasModifiers = false;
123           if (fToken == TokenNameCOMMENT_PHPDOC) {
124             phpdocOffset = fScanner.getCurrentTokenStartPosition();
125             phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
126             getNextToken();
127             while (fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
128                 || fToken == TokenNameprotected || fToken == TokenNameprivate || fToken == TokenNameabstract) {
129               hasModifiers = true;
130               getNextToken();
131             }
132             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
133               break;
134             }
135           }
136           if (fToken == TokenNamefunction) {
137             getNextToken();
138             if (fToken == TokenNameAND) {
139               getNextToken();
140             }
141             if (fToken == TokenNameIdentifier) {
142               ident = fScanner.getCurrentIdentifierSource();
143               if (parent != null && equalCharArrays(parent, ident)) {
144                 // constructor function
145                 addIdentifierInformation('k', ident, buf, phpdocOffset, phpdocLength);
146               } else {
147                 if (parent != null) {
148                   // class method function
149                   addIdentifierInformation('m', ident, buf, phpdocOffset, phpdocLength);
150                 } else {
151                   // nested function ?!
152                   addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
153                 }
154               }
155               getNextToken();
156               parseDeclarations(null, buf, true);
157             }
158           } else if (fToken == TokenNameclass || fToken == TokenNameinterface) {
159             getNextToken();
160             if (fToken == TokenNameIdentifier) {
161               ident = fScanner.getCurrentIdentifierSource();
162               addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
163               getNextToken();
164               //skip tokens for classname, extends and others until we have
165               // the opening '{'
166               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
167                 getNextToken();
168               }
169               parseDeclarations(ident, buf, true);
170             }
171           } else if (fToken == TokenNamevar || hasModifiers || fToken == TokenNamestatic || fToken == TokenNamefinal
172               || fToken == TokenNamepublic || fToken == TokenNameprotected || fToken == TokenNameprivate) {
173             while (fToken == TokenNamevar || fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
174                 || fToken == TokenNameprotected || fToken == TokenNameprivate) {
175               getNextToken();
176             }
177             if (fToken == TokenNameVariable) {
178               ident = fScanner.getCurrentIdentifierSource();
179               classVariable = new char[ident.length - 1];
180               System.arraycopy(ident, 1, classVariable, 0, ident.length - 1);
181               addClassVariableInformation('v', classVariable, buf, phpdocOffset, phpdocLength);
182               getNextToken();
183             }
184           } else if (!hasModifiers && fToken == TokenNameIdentifier) {
185             ident = fScanner.getCurrentIdentifierSource();
186             getNextToken();
187             if (ident.length == 6 && ident[0] == 'd' && ident[1] == 'e' && ident[2] == 'f' && ident[3] == 'i' && ident[4] == 'n'
188                 && ident[5] == 'e') {
189               if (fToken == TokenNameLPAREN) {
190                 getNextToken();
191                 if (fToken == TokenNameStringDoubleQuote) {
192                   ident = fScanner.getCurrentStringLiteralSource();
193                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
194                   getNextToken();
195                 }
196               }
197             }
198           } else if (fToken == TokenNameglobal) {
199             // global variable
200             while (fToken != TokenNameEOF && fToken != TokenNameERROR && fToken != TokenNameSEMICOLON && fToken != TokenNameLBRACE
201                 && fToken != TokenNameRBRACE) {
202               getNextToken();
203               if (fToken == TokenNameVariable) {
204                 ident = fScanner.getCurrentIdentifierSource();
205                 addIdentifierInformation('g', ident, buf, phpdocOffset, phpdocLength);
206               }
207             }
208           } else if (fToken == TokenNameLBRACE) {
209             getNextToken();
210             counter++;
211           } else if (fToken == TokenNameRBRACE) {
212             getNextToken();
213             --counter;
214             if (counter == 0 && goBack) {
215               return;
216             }
217           } else {
218             getNextToken();
219           }
220         }
221       } catch (SyntaxError e) {
222         // TODO Auto-generated catch block
223         e.printStackTrace();
224       }
225     }
226
227     synchronized public void parseIdentifiers(char[] charArray, StringBuffer buf) {
228       char[] ident;
229       String identifier;
230       int counter = 0;
231       boolean hasModifiers = false;
232       int phpdocOffset = -1;
233       int phpdocLength = -1;
234       fScanner.setSource(charArray);
235       fScanner.setPHPMode(false);
236       fToken = TokenNameEOF;
237       getNextToken();
238       try {
239         while (fToken != TokenNameEOF) { // && fToken != TokenNameERROR) {
240           phpdocOffset = -1;
241           hasModifiers = false;
242           if (fToken == TokenNameCOMMENT_PHPDOC) {
243             phpdocOffset = fScanner.getCurrentTokenStartPosition();
244             phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
245             getNextToken();
246             while (fToken == TokenNamestatic || fToken == TokenNamefinal || fToken == TokenNamepublic
247                 || fToken == TokenNameprotected || fToken == TokenNameprivate || fToken == TokenNameabstract) {
248               hasModifiers = true;
249               getNextToken();
250             }
251             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
252               break;
253             }
254           }
255           if (fToken == TokenNamefunction) {
256             getNextToken();
257             if (fToken == TokenNameAND) {
258               getNextToken();
259             }
260             if (fToken == TokenNameIdentifier) {
261               ident = fScanner.getCurrentIdentifierSource();
262               addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
263               getNextToken();
264               parseDeclarations(null, buf, true);
265             }
266           } else if (fToken == TokenNameclass || fToken == TokenNameinterface) {
267             getNextToken();
268             if (fToken == TokenNameIdentifier) {
269               ident = fScanner.getCurrentIdentifierSource();
270               addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
271               getNextToken();
272               //skip fTokens for classname, extends and others until we have
273               // the opening '{'
274               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
275                 getNextToken();
276               }
277               parseDeclarations(ident, buf, true);
278             }
279           } else if (fToken == TokenNameVariable) {
280             // global variable
281             ident = fScanner.getCurrentIdentifierSource();
282             addIdentifierInformation('g', ident, buf, phpdocOffset, phpdocLength);
283             getNextToken();
284           } else if (!hasModifiers && fToken == TokenNameIdentifier) {
285             ident = fScanner.getCurrentIdentifierSource();
286             getNextToken();
287             if (ident.length == 6 && ident[0] == 'd' && ident[1] == 'e' && ident[2] == 'f' && ident[3] == 'i' && ident[4] == 'n'
288                 && ident[5] == 'e') {
289               if (fToken == TokenNameLPAREN) {
290                 getNextToken();
291                 if (fToken == TokenNameStringDoubleQuote) {
292                   ident = fScanner.getCurrentStringLiteralSource();
293                   addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
294                   getNextToken();
295                 }
296               }
297             }
298           } else {
299             getNextToken();
300           }
301         }
302       } catch (SyntaxError e) {
303         // TODO Auto-generated catch block
304         e.printStackTrace();
305       }
306     }
307   }
308
309   class StringComparator implements Comparator {
310     public int compare(Object o1, Object o2) {
311       String s1 = (String) o1;
312       String s2 = (String) o2;
313       return s1.compareTo(s2);
314       //        return s1.toUpperCase().compareTo(s2.toUpperCase());
315     }
316
317     public boolean equals(Object o) {
318       String s = (String) o;
319       return compare(this, o) == 0;
320     }
321   }
322
323   private HashMap fFileMap;
324
325   private String fFilename;
326
327   private TreeMap fIndentifierMap;
328
329   public IdentifierIndexManager(String filename) {
330     fFilename = filename;
331     initialize();
332     readFile();
333   }
334
335   /**
336    * Check if 2 char arrays are equal
337    * 
338    * @param a
339    * @param b
340    * @return
341    */
342   private static boolean equalCharArrays(char[] a, char[] b) {
343     if (a.length != b.length) {
344       return false;
345     }
346     for (int i = 0; i < b.length; i++) {
347       if (a[i] != b[i]) {
348         return false;
349       }
350     }
351     return true;
352   }
353
354   public LineCreator createLineCreator() {
355     return new LineCreator();
356   }
357
358   /**
359    * Add the information for a given IFile resource
360    *  
361    */
362   public void addFile(IFile fileToParse) {
363     //    InputStream iStream;
364     LineCreator lineCreator = createLineCreator();
365     try {
366       addInputStream(new BufferedInputStream(fileToParse.getContents()), fileToParse.getProjectRelativePath().toString(),
367           lineCreator);
368     } catch (CoreException e1) {
369       // TODO Auto-generated catch block
370       e1.printStackTrace();
371     }
372   }
373
374   /**
375    * @param fileToParse
376    * @param lineCreator
377    * @throws CoreException
378    */
379   public void addInputStream(InputStream stream, String filePath, LineCreator lineCreator) throws CoreException {
380     try {
381       StringBuffer lineBuffer = new StringBuffer();
382       lineBuffer.append(filePath);
383       int lineLength = lineBuffer.length();
384       lineCreator.parseIdentifiers(Util.getInputStreamAsCharArray(stream, -1, null), lineBuffer);
385       //      if (lineLength != lineBuffer.length()) {
386       // always add the file for Open Include Action
387       addLine(lineBuffer.toString());
388       //      }
389     } catch (IOException e) {
390       e.printStackTrace();
391     } finally {
392       try {
393         if (stream != null) {
394           stream.close();
395         }
396       } catch (IOException e) {
397       }
398     }
399   }
400
401   /**
402    * Adds a line of the index file for function, class, class-method and class-variable names
403    * 
404    * @param line
405    */
406   private void addLine(String line) {
407     StringTokenizer tokenizer;
408     String phpFileName = null;
409     String token;
410     String identifier = null;
411     String classname = null;
412     String offset = null;
413     PHPIdentifierLocation phpIdentifier = null;
414     boolean tokenExists = false;
415     tokenizer = new StringTokenizer(line, "\t");
416     // first token contains the filename:
417     if (tokenizer.hasMoreTokens()) {
418       phpFileName = tokenizer.nextToken();
419       //System.out.println(token);
420     } else {
421       return;
422     }
423     // all the other tokens are identifiers:
424     while (tokenizer.hasMoreTokens()) {
425       token = tokenizer.nextToken();
426       //System.out.println(token);
427       switch (token.charAt(0)) {
428       case 'c':
429         // class name
430         identifier = token.substring(1);
431         classname = identifier;
432         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
433         break;
434       case 'd':
435         // define
436         identifier = token.substring(1);
437         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
438         break;
439       case 'f':
440         // function name
441         identifier = token.substring(1);
442         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
443         break;
444       case 'g':
445         // global variable
446         identifier = token.substring(1);
447         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
448         break;
449       case 'k':
450         // constructor function name
451         identifier = token.substring(1);
452         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CONSTRUCTOR, phpFileName);
453         break;
454       case 'm':
455         //method inside a class
456         identifier = token.substring(1);
457         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
458         break;
459       case 'v':
460         // variable inside a class
461         identifier = token.substring(1);
462         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
463         break;
464       case 'o':
465         // offset information
466         identifier = null;
467         if (phpIdentifier != null) {
468           offset = token.substring(1);
469           phpIdentifier.setOffset(Integer.parseInt(offset));
470         }
471         break;
472       case 'p':
473         // PHPdoc offset information
474         identifier = null;
475         if (phpIdentifier != null) {
476           offset = token.substring(1);
477           phpIdentifier.setPHPDocOffset(Integer.parseInt(offset));
478         }
479         break;
480       case 'l':
481         // PHPdoc length information
482         identifier = null;
483         if (phpIdentifier != null) {
484           offset = token.substring(1);
485           phpIdentifier.setPHPDocLength(Integer.parseInt(offset));
486         }
487         break;
488       default:
489         PHPeclipsePlugin.log(IStatus.ERROR, "Unknown token character in IdentifierIndexManager: " + token.charAt(0));
490         identifier = null;
491         phpIdentifier = null;
492         classname = null;
493       }
494       if (identifier != null && phpIdentifier != null) {
495         tokenExists = true;
496         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
497         if (list == null) {
498           list = new ArrayList();
499           list.add(phpIdentifier);
500           fIndentifierMap.put(identifier, list);
501         } else {
502           boolean flag = false;
503           for (int i = 0; i < list.size(); i++) {
504             if (list.get(i).equals(phpIdentifier)) {
505               flag = true;
506               break;
507             }
508           }
509           if (flag == false) {
510             list.add(phpIdentifier);
511           }
512         }
513       }
514     }
515     //    if (tokenExists) {
516     fFileMap.put(phpFileName, line);
517     //    }
518   }
519
520   /**
521    * Change the information for a given IFile resource
522    *  
523    */
524   public void changeFile(IFile fileToParse) {
525     removeFile(fileToParse);
526     addFile(fileToParse);
527   }
528
529   /**
530    * Get a list of all PHPIdentifierLocation object's associated with an identifier
531    * 
532    * @param identifier
533    * @return
534    */
535   public List getLocations(String identifier) {
536     return (List) fIndentifierMap.get(identifier);
537   }
538
539   /**
540    * Initialize (i.e. clear) the current index information
541    *  
542    */
543   public void initialize() {
544     fIndentifierMap = new TreeMap(new StringComparator());
545     fFileMap = new HashMap();
546   }
547
548   private void readFile() {
549     FileReader fileReader;
550     try {
551       fileReader = new FileReader(fFilename);
552       BufferedReader bufferedReader = new BufferedReader(fileReader);
553       String line;
554       while (bufferedReader.ready()) {
555         // all entries for one file are in a line
556         // separated by tabs !
557         line = bufferedReader.readLine();
558         addLine(line);
559       }
560       fileReader.close();
561     } catch (FileNotFoundException e) {
562       // ignore this
563       // TODO DialogBox which asks the user if she/he likes to build new index?
564     } catch (IOException e) {
565       // TODO Auto-generated catch block
566       e.printStackTrace();
567     }
568   }
569
570   /**
571    * Remove the information for a given IFile resource
572    *  
573    */
574   public void removeFile(IFile fileToParse) {
575     //    String line = (String)
576     // fFileMap.get(fileToParse.getLocation().toString());
577     String line = (String) fFileMap.get(fileToParse.getProjectRelativePath().toString());
578     if (line != null) {
579       removeLine(line);
580     }
581   }
582
583   /**
584    * Removes a line of the index file for function, class, class-method and class-variable names
585    * 
586    * @param line
587    */
588   private void removeLine(String line) {
589     StringTokenizer tokenizer;
590     String phpFileName = null;
591     String token;
592     String identifier = null;
593     String classname = null;
594     PHPIdentifier phpIdentifier = null;
595     boolean tokenExists = false;
596     tokenizer = new StringTokenizer(line, "\t");
597     // first token contains the filename:
598     if (tokenizer.hasMoreTokens()) {
599       phpFileName = tokenizer.nextToken();
600       //System.out.println(token);
601     } else {
602       return;
603     }
604     int offset = -1;
605     // all the other tokens are identifiers:
606     while (tokenizer.hasMoreTokens()) {
607       token = tokenizer.nextToken();
608       //System.out.println(token);
609       switch (token.charAt(0)) {
610       case 'c':
611         // class name
612         identifier = token.substring(1);
613         classname = identifier;
614         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
615         break;
616       case 'd':
617         // define
618         identifier = token.substring(1);
619         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
620         break;
621       case 'f':
622         // function name
623         identifier = token.substring(1);
624         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
625         break;
626       case 'g':
627         // global variable
628         identifier = token.substring(1);
629         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.GLOBAL_VARIABLE, phpFileName);
630         break;
631       case 'k':
632         // constructor function name
633         identifier = token.substring(1);
634         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CONSTRUCTOR, phpFileName);
635         break;
636       case 'm':
637         //method inside a class
638         identifier = token.substring(1);
639         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
640         break;
641       case 'o':
642         // offset information
643         identifier = null;
644         break;
645       case 'p':
646         // PHPdoc offset information
647         identifier = null;
648         break;
649       case 'l':
650         // PHPdoc length information
651         identifier = null;
652         break;
653       case 'v':
654         // variable inside a class
655         identifier = token.substring(1);
656         phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
657         break;
658       default:
659         PHPeclipsePlugin.log(IStatus.ERROR, "Unknown token character in IdentifierIndexManager: " + token.charAt(0));
660         identifier = null;
661         phpIdentifier = null;
662         classname = null;
663       }
664       if (identifier != null && phpIdentifier != null) {
665         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
666         if (list == null) {
667         } else {
668           for (int i = 0; i < list.size(); i++) {
669             if (list.get(i).equals(phpIdentifier)) {
670               list.remove(i);
671               break;
672             }
673           }
674           if (list.size() == 0) {
675             fIndentifierMap.remove(identifier);
676           }
677         }
678       }
679     }
680     fFileMap.remove(phpFileName);
681   }
682
683   /**
684    * Save the current index information in the projects index file
685    *  
686    */
687   public void writeFile() {
688     FileWriter fileWriter;
689     try {
690       fileWriter = new FileWriter(fFilename);
691       String line;
692       Collection collection = fFileMap.values();
693       Iterator iterator = collection.iterator();
694       while (iterator.hasNext()) {
695         line = (String) iterator.next();
696         fileWriter.write(line + '\n');
697       }
698       fileWriter.close();
699     } catch (FileNotFoundException e) {
700       // ignore exception; project is deleted by user
701     } catch (IOException e) {
702       // TODO Auto-generated catch block
703       e.printStackTrace();
704     }
705   }
706
707   /**
708    * @param fromKey
709    * @param toKey
710    * @return
711    */
712   public SortedMap getIdentifierMap() {
713     return fIndentifierMap;
714   }
715
716   synchronized public List getFileList(String filePattern) {
717     Set set = fFileMap.keySet();
718     if (set.isEmpty()) {
719       return null;
720     }
721     Iterator iter = set.iterator();
722     ArrayList list = new ArrayList();
723     String fileName;
724     int index;
725     while (iter.hasNext()) {
726       fileName = (String) iter.next();
727       if ((index = fileName.indexOf(filePattern)) != -1 && fileName.length() == (index + filePattern.length())) {
728         list.add(fileName);
729       }
730     }
731     return list;
732   }
733 }