1 package net.sourceforge.phpeclipse.builder;
 
   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.SortedMap;
 
  17 import java.util.StringTokenizer;
 
  18 import java.util.TreeMap;
 
  20 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
 
  21 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
 
  22 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
 
  23 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
 
  24 import net.sourceforge.phpdt.internal.compiler.util.Util;
 
  25 import net.sourceforge.phpeclipse.obfuscator.PHPIdentifier;
 
  27 import org.eclipse.core.resources.IFile;
 
  28 import org.eclipse.core.runtime.CoreException;
 
  31  * Manages the identifer index information for a specific project
 
  34 public class IdentifierIndexManager {
 
  36   public class LineCreator implements ITerminalSymbols {
 
  38     private Scanner fScanner;
 
  41     public LineCreator() {
 
  42       fScanner = new Scanner(true, false);
 
  46      * Add the information of the current identifier to the line
 
  48      * @param typeOfIdentifier the type of the identifier ('c'lass, 'd'efine, 'f'unction, 'm'ethod, 'v'ariable)
 
  49      * @param identifier current identifier
 
  50      * @param line Buffer for the current index line
 
  51      * @param phpdocOffset the offset of the PHPdoc comment if available
 
  52      * @param phpdocLength the length of the PHPdoc comment if available
 
  54     private void addIdentifierInformation(
 
  55       char typeOfIdentifier,
 
  62       line.append(typeOfIdentifier);
 
  63       line.append(identifier);
 
  64       line.append("\to"); // Offset 
 
  65       line.append(fScanner.getCurrentTokenStartPosition());
 
  66       if (phpdocOffset >= 0) {
 
  67         line.append("\tp"); // phpdoc offset
 
  68         line.append(phpdocOffset);
 
  69         line.append("\tl"); // phpdoc length
 
  70         line.append(phpdocLength);
 
  75      * Get the next token from input
 
  77     private void getNextToken() {
 
  79         fToken = fScanner.getNextToken();
 
  81           int currentEndPosition = fScanner.getCurrentTokenEndPosition();
 
  82           int currentStartPosition = fScanner.getCurrentTokenStartPosition();
 
  84           System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
 
  85           System.out.println(fScanner.toStringAction(fToken));
 
  88       } catch (InvalidInputException e) {
 
  91       fToken = TokenNameERROR;
 
  94     private void parseDeclarations(char[] parent, StringBuffer buf, boolean goBack) {
 
  98       int phpdocOffset = -1;
 
  99       int phpdocLength = -1;
 
 102         while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
 
 104           if (fToken == TokenNameCOMMENT_PHPDOC) {
 
 105             phpdocOffset = fScanner.getCurrentTokenStartPosition();
 
 106             phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
 
 108             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
 
 112           if (fToken == TokenNamevar) {
 
 114             if (fToken == TokenNameVariable) {
 
 115               ident = fScanner.getCurrentIdentifierSource();
 
 116               classVariable = new char[ident.length - 1];
 
 117               System.arraycopy(ident, 1, classVariable, 0, ident.length - 1);
 
 118               addIdentifierInformation('v', classVariable, buf, phpdocOffset, phpdocLength);
 
 121           } else if (fToken == TokenNamefunction) {
 
 123             if (fToken == TokenNameAND) {
 
 126             if (fToken == TokenNameIdentifier) {
 
 127               ident = fScanner.getCurrentIdentifierSource();
 
 128               if (parent != null && equalCharArrays(parent, ident)) {
 
 129                 // constructor function
 
 130                 addIdentifierInformation('k', ident, buf, phpdocOffset, phpdocLength);
 
 132                 if (parent != null) {
 
 133                   // class method function
 
 134                   addIdentifierInformation('m', ident, buf, phpdocOffset, phpdocLength);
 
 136                   // nested function ?!
 
 137                   addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
 
 141               parseDeclarations(null, buf, true);
 
 143           } else if (fToken == TokenNameclass) {
 
 145             if (fToken == TokenNameIdentifier) {
 
 146               ident = fScanner.getCurrentIdentifierSource();
 
 147               addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
 
 150               //skip tokens for classname, extends and others until we have the opening '{'
 
 151               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
 
 154               parseDeclarations(ident, buf, true);
 
 156           } else if (fToken == TokenNamedefine) {
 
 158             if (fToken == TokenNameLPAREN) {
 
 160               if (fToken == TokenNameStringLiteral) {
 
 161                 ident = fScanner.getCurrentStringLiteralSource();
 
 162                 addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
 
 166           } else if ((fToken == TokenNameLBRACE) || (fToken == TokenNameDOLLAR_LBRACE)) {
 
 169           } else if (fToken == TokenNameRBRACE) {
 
 172             if (counter == 0 && goBack) {
 
 179       } catch (SyntaxError e) {
 
 180         // TODO Auto-generated catch block
 
 185     public void parseIdentifiers(char[] charArray, StringBuffer buf) {
 
 189       int phpdocOffset = -1;
 
 190       int phpdocLength = -1;
 
 192       fScanner.setSource(charArray);
 
 193       fScanner.setPHPMode(false);
 
 194       fToken = TokenNameEOF;
 
 198         while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
 
 200           if (fToken == TokenNameCOMMENT_PHPDOC) {
 
 201             phpdocOffset = fScanner.getCurrentTokenStartPosition();
 
 202             phpdocLength = fScanner.getCurrentTokenEndPosition() - fScanner.getCurrentTokenStartPosition() + 1;
 
 204             if (fToken == TokenNameEOF || fToken == TokenNameERROR) {
 
 208           if (fToken == TokenNamefunction) {
 
 210             if (fToken == TokenNameAND) {
 
 213             if (fToken == TokenNameIdentifier) {
 
 214               ident = fScanner.getCurrentIdentifierSource();
 
 215               addIdentifierInformation('f', ident, buf, phpdocOffset, phpdocLength);
 
 217               parseDeclarations(null, buf, true);
 
 219           } else if (fToken == TokenNameclass) {
 
 221             if (fToken == TokenNameIdentifier) {
 
 222               ident = fScanner.getCurrentIdentifierSource();
 
 223               addIdentifierInformation('c', ident, buf, phpdocOffset, phpdocLength);
 
 226               //skip fTokens for classname, extends and others until we have the opening '{'
 
 227               while (fToken != TokenNameLBRACE && fToken != TokenNameEOF && fToken != TokenNameERROR) {
 
 231               parseDeclarations(ident, buf, true);
 
 234           } else if (fToken == TokenNamedefine) {
 
 236             if (fToken == TokenNameLPAREN) {
 
 238               if (fToken == TokenNameStringLiteral) {
 
 239                 ident = fScanner.getCurrentStringLiteralSource();
 
 240                 addIdentifierInformation('d', ident, buf, phpdocOffset, phpdocLength);
 
 248       } catch (SyntaxError e) {
 
 249         // TODO Auto-generated catch block
 
 255   class StringComparator implements Comparator {
 
 256     public int compare(Object o1, Object o2) {
 
 257       String s1 = (String) o1;
 
 258       String s2 = (String) o2;
 
 259       return s1.compareTo(s2);
 
 260       //        return s1.toUpperCase().compareTo(s2.toUpperCase()); 
 
 262     public boolean equals(Object o) {
 
 263       String s = (String) o;
 
 264       return compare(this, o) == 0;
 
 268   private HashMap fFileMap;
 
 269   private String fFilename;
 
 270   private TreeMap fIndentifierMap;
 
 272   public IdentifierIndexManager(String filename) {
 
 273     fFilename = filename;
 
 279    * Check if 2 char arrays are equal
 
 285   private static boolean equalCharArrays(char[] a, char[] b) {
 
 286     if (a.length != b.length) {
 
 289     for (int i = 0; i < b.length; i++) {
 
 298    * Add the information for a given IFile resource
 
 301   public void addFile(IFile fileToParse) {
 
 302     //    InputStream iStream;
 
 303     LineCreator lineCreator = new LineCreator();
 
 305       //      iStream = fileToParse.getContents();
 
 307       //      StringBuffer buf = new StringBuffer();
 
 310       //        while ((c0 = iStream.read()) != (-1)) {
 
 311       //          buf.append((char) c0);
 
 313       //      } catch (IOException e) {
 
 316       InputStream stream = null;
 
 318         stream = new BufferedInputStream(fileToParse.getContents());
 
 320         StringBuffer lineBuffer = new StringBuffer();
 
 321         lineBuffer.append(fileToParse.getFullPath().toString());
 
 322         int lineLength = lineBuffer.length();
 
 323         // lineCreator.parseIdentifiers(buf.toString().toCharArray(), lineBuffer);
 
 324         lineCreator.parseIdentifiers(Util.getInputStreamAsCharArray(stream, -1, null), lineBuffer);
 
 325         if (lineLength != lineBuffer.length()) {
 
 326           addLine(lineBuffer.toString());
 
 328       } catch (IOException e) {
 
 332           if (stream != null) {
 
 335         } catch (IOException e) {
 
 338     } catch (CoreException e1) {
 
 339       // TODO Auto-generated catch block
 
 340       e1.printStackTrace();
 
 345    * Adds a line of the index file for function, class, class-method and class-variable names
 
 349   private void addLine(String line) {
 
 350     StringTokenizer tokenizer;
 
 351     String phpFileName = null;
 
 353     String identifier = null;
 
 354     String classname = null;
 
 355     String offset = null;
 
 356     PHPIdentifierLocation phpIdentifier = null;
 
 357     boolean tokenExists = false;
 
 359     tokenizer = new StringTokenizer(line, "\t");
 
 360     // first token contains the filename:
 
 361     if (tokenizer.hasMoreTokens()) {
 
 362       phpFileName = tokenizer.nextToken();
 
 363       //System.out.println(token);
 
 367     // all the other tokens are identifiers:
 
 368     while (tokenizer.hasMoreTokens()) {
 
 369       token = tokenizer.nextToken();
 
 370       //System.out.println(token);
 
 371       switch (token.charAt(0)) {
 
 372         case 'c' : // class name
 
 373           identifier = token.substring(1);
 
 374           classname = identifier;
 
 375           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
 
 378           identifier = token.substring(1);
 
 379           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
 
 381         case 'f' : // function name
 
 382           identifier = token.substring(1);
 
 383           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
 
 385         case 'k' : // constructor function name
 
 386           identifier = token.substring(1);
 
 387           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CONSTRUCTOR, phpFileName);
 
 389         case 'm' : //method inside a class
 
 390           identifier = token.substring(1);
 
 391           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
 
 393         case 'v' : // variable inside a class
 
 394           identifier = token.substring(1);
 
 395           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
 
 397         case 'o' : // offset information
 
 399           if (phpIdentifier != null) {
 
 400             offset = token.substring(1);
 
 401             phpIdentifier.setOffset(Integer.parseInt(offset));
 
 404         case 'p' : // PHPdoc offset information
 
 406           if (phpIdentifier != null) {
 
 407             offset = token.substring(1);
 
 408             phpIdentifier.setPHPDocOffset(Integer.parseInt(offset));
 
 411         case 'l' : // PHPdoc length information
 
 413           if (phpIdentifier != null) {
 
 414             offset = token.substring(1);
 
 415             phpIdentifier.setPHPDocLength(Integer.parseInt(offset));
 
 420           phpIdentifier = null;
 
 423       if (identifier != null && phpIdentifier != null) {
 
 425         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
 
 427           list = new ArrayList();
 
 428           list.add(phpIdentifier);
 
 429           fIndentifierMap.put(identifier, list);
 
 431           boolean flag = false;
 
 432           for (int i = 0; i < list.size(); i++) {
 
 433             if (list.get(i).equals(phpIdentifier)) {
 
 439             list.add(phpIdentifier);
 
 445       fFileMap.put(phpFileName, line);
 
 450    * Change the information for a given IFile resource
 
 453   public void changeFile(IFile fileToParse) {
 
 454     removeFile(fileToParse);
 
 455     addFile(fileToParse);
 
 459    * Get a list of all PHPIdentifierLocation object's associated with an identifier
 
 464   public List getLocations(String identifier) {
 
 465     return (List) fIndentifierMap.get(identifier);
 
 469    * Initialize (i.e. clear) the current index information
 
 472   public void initialize() {
 
 473     fIndentifierMap = new TreeMap(new StringComparator());
 
 474     fFileMap = new HashMap();
 
 477   private void readFile() {
 
 479     FileReader fileReader;
 
 481       fileReader = new FileReader(fFilename);
 
 483       BufferedReader bufferedReader = new BufferedReader(fileReader);
 
 486       while (bufferedReader.ready()) {
 
 487         // all entries for one file are in a line
 
 488         // separated by tabs !
 
 489         line = bufferedReader.readLine();
 
 494     } catch (FileNotFoundException e) {
 
 496       // TODO DialogBox which asks the user if she/he likes to build new index?
 
 497     } catch (IOException e) {
 
 498       // TODO Auto-generated catch block
 
 505    * Remove the information for a given IFile resource
 
 508   public void removeFile(IFile fileToParse) {
 
 509     //    String line = (String) fFileMap.get(fileToParse.getLocation().toString());
 
 510     String line = (String) fFileMap.get(fileToParse.getFullPath().toString());
 
 517    * Removes a line of the index file for function, class, class-method and class-variable names
 
 521   private void removeLine(String line) {
 
 522     StringTokenizer tokenizer;
 
 523     String phpFileName = null;
 
 525     String identifier = null;
 
 526     String classname = null;
 
 527     PHPIdentifier phpIdentifier = null;
 
 528     boolean tokenExists = false;
 
 530     tokenizer = new StringTokenizer(line, "\t");
 
 531     // first token contains the filename:
 
 532     if (tokenizer.hasMoreTokens()) {
 
 533       phpFileName = tokenizer.nextToken();
 
 534       //System.out.println(token);
 
 538     // all the other tokens are identifiers:
 
 539     while (tokenizer.hasMoreTokens()) {
 
 540       token = tokenizer.nextToken();
 
 541       //System.out.println(token);
 
 542       switch (token.charAt(0)) {
 
 543         case 'c' : // class name
 
 544           identifier = token.substring(1);
 
 545           classname = identifier;
 
 546           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CLASS, phpFileName);
 
 549           identifier = token.substring(1);
 
 550           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.DEFINE, phpFileName);
 
 552         case 'f' : // function name
 
 553           identifier = token.substring(1);
 
 554           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.FUNCTION, phpFileName);
 
 556         case 'k' : // constructor function name
 
 557           identifier = token.substring(1);
 
 558           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.CONSTRUCTOR, phpFileName);
 
 560         case 'm' : //method inside a class
 
 561           identifier = token.substring(1);
 
 562           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.METHOD, phpFileName, classname);
 
 564         case 'v' : // variable inside a class
 
 565           identifier = token.substring(1);
 
 566           phpIdentifier = new PHPIdentifierLocation(identifier, PHPIdentifier.VARIABLE, phpFileName, classname);
 
 570           phpIdentifier = null;
 
 573       if (identifier != null && phpIdentifier != null) {
 
 574         ArrayList list = (ArrayList) fIndentifierMap.get(identifier);
 
 577           for (int i = 0; i < list.size(); i++) {
 
 578             if (list.get(i).equals(phpIdentifier)) {
 
 583           if (list.size() == 0) {
 
 584             fIndentifierMap.remove(identifier);
 
 589     fFileMap.remove(phpFileName);
 
 593    * Save the current index information in the projects index file
 
 596   public void writeFile() {
 
 597     FileWriter fileWriter;
 
 599       fileWriter = new FileWriter(fFilename);
 
 601       Collection collection = fFileMap.values();
 
 602       Iterator iterator = collection.iterator();
 
 603       while (iterator.hasNext()) {
 
 604         line = (String) iterator.next();
 
 605         fileWriter.write(line + '\n');
 
 608     } catch (FileNotFoundException e) {
 
 609       // ignore exception; project is deleted by user
 
 610     } catch (IOException e) {
 
 611       // TODO Auto-generated catch block
 
 621   public SortedMap getIdentifierMap() {
 
 622     return fIndentifierMap;