9df47df9f1f5252f212fd3964c039367da60e30e
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / mover / obfuscator / PHPObfuscatorMover.java
1 package net.sourceforge.phpeclipse.mover.obfuscator;
2
3 import java.io.BufferedReader;
4 import java.io.BufferedWriter;
5 import java.io.File;
6 import java.io.FileInputStream;
7 import java.io.FileOutputStream;
8 import java.io.FileReader;
9 import java.io.FileWriter;
10 import java.io.IOException;
11 //import java.security.MessageDigest;
12 //import java.security.NoSuchAlgorithmException;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15
16 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
17 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
18 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
19 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
20 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
21 import net.sourceforge.phpeclipse.mover.DefaultMover;
22 import net.sourceforge.phpeclipse.views.PHPConsole;
23
24 import org.eclipse.jface.preference.IPreferenceStore;
25
26 /**
27  * Obfuscate the file with the PHP Scanner
28  */
29 public class PHPObfuscatorMover extends DefaultMover implements ITerminalSymbols {
30
31   private Scanner fScanner;
32   private int fToken;
33  // private MessageDigest fAlgorithm;
34   private int fCounter;
35
36   protected HashMap fIdentifierMap;
37
38   /**
39    * buffer, for obvious reasons access to this buffer must
40    * be synchronized
41    */
42   protected byte[] bytes = new byte[1024];
43   /**
44    * Creates a PHPAnalyzer
45    * @param console reports error to the PHPConsole
46    */
47   public PHPObfuscatorMover(PHPConsole console, Scanner scanner, HashMap identifierMap) {
48     super(console);
49     this.fScanner = scanner;
50     this.fIdentifierMap = identifierMap;
51     this.fCounter = 0;
52 //    try {
53 //      this.fAlgorithm = MessageDigest.getInstance("MD5");
54 //    } catch (NoSuchAlgorithmException e) {
55 //      System.out.println(e.toString());
56 //    }
57   }
58
59   /**
60    * Return the name the file would have after moving. In this case,
61    * it's left unchanged.
62    * @param file file the mover would have to move
63    * @return the extension it would give the file in the target directory
64    */
65   public String getTargetName(File file) {
66     return file.getName();
67   }
68
69   /**
70    * gets the next token from input
71    */
72   private void getNextToken() {
73
74     try {
75       fToken = fScanner.getNextToken();
76       if (Scanner.DEBUG) {
77         int currentEndPosition = fScanner.getCurrentTokenEndPosition();
78         int currentStartPosition = fScanner.getCurrentTokenStartPosition();
79
80         System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
81         System.out.println(fScanner.toStringAction(fToken));
82       }
83       return;
84     } catch (InvalidInputException e) {
85
86     }
87     fToken = TokenNameERROR;
88   }
89
90   private boolean obfuscate(StringBuffer buf) {
91     char[] ident;
92     String identifier;
93     PHPIdentifier value;
94
95     int startPosition = 0;
96     int lastPosition = 0;
97
98     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
99     try {
100       while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
101         if (fToken == TokenNameVariable) {
102           identifier = new String(fScanner.getCurrentIdentifierSource());
103           lastPosition = fScanner.startPosition;
104           int len = lastPosition - startPosition;
105           buf.append(fScanner.source, startPosition, len);
106           value = (PHPIdentifier) fIdentifierMap.get(identifier);
107           if (value != null) {
108             String obfuscatedIdentifier = value.getIdentifier();
109             if (obfuscatedIdentifier == null) {
110               buf.append("$v" + Integer.toString(fCounter));
111               value.setIdentifier("$v" + Integer.toString(fCounter++));
112             } else {
113               buf.append(obfuscatedIdentifier);
114             }
115             //     System.out.println(hexString.toString());
116           } else {
117             buf.append(identifier);
118           }
119           startPosition = fScanner.currentPosition;
120           getNextToken();
121         } else if (fToken == TokenNameIdentifier) {
122           identifier = new String(fScanner.getCurrentIdentifierSource());
123           lastPosition = fScanner.startPosition;
124           int len = lastPosition - startPosition;
125           buf.append(fScanner.source, startPosition, len);
126           value = (PHPIdentifier) fIdentifierMap.get(identifier);
127           if (value != null) {
128             String obfuscatedIdentifier = value.getIdentifier();
129             if (obfuscatedIdentifier == null) {
130               buf.append("_" + Integer.toString(fCounter));
131               value.setIdentifier("_" + Integer.toString(fCounter++));
132             } else {
133               buf.append(obfuscatedIdentifier);
134             }
135             //     System.out.println(hexString.toString());
136           } else {
137             buf.append(identifier);
138           }
139           startPosition = fScanner.currentPosition;
140           getNextToken();
141
142         } else if (fToken == TokenNameCOMMENT_LINE || fToken == TokenNameCOMMENT_BLOCK || fToken == TokenNameCOMMENT_PHPDOC) {
143           lastPosition = fScanner.startPosition;
144           buf.append(fScanner.source, startPosition, lastPosition - startPosition);
145           startPosition = fScanner.currentPosition;
146           getNextToken();
147         } else if (fToken == TokenNameStringLiteral) {
148           char currentCharacter;
149           int i = fScanner.startPosition;
150           ArrayList varList = new ArrayList();
151
152           lastPosition = fScanner.startPosition;
153           int len = lastPosition - startPosition;
154           buf.append(fScanner.source, startPosition, len);
155
156           while (i < fScanner.currentPosition) {
157             currentCharacter = fScanner.source[i++];
158             if (currentCharacter == '$' && fScanner.source[i-2]!='\\') {
159               StringBuffer varName = new StringBuffer();
160               varName.append("$");
161               while (i < fScanner.currentPosition) {
162                 currentCharacter = fScanner.source[i++];
163                 if (!Scanner.isPHPIdentifierPart(currentCharacter)) {
164                   break; // while loop
165                 }
166                 varName.append(currentCharacter);
167               }
168               varList.add(varName.toString());
169             }
170           }
171           StringBuffer stringLiteral = new StringBuffer();
172           stringLiteral.append(fScanner.source, fScanner.startPosition, fScanner.currentPosition - fScanner.startPosition);
173           String stringIdent;
174           String replacement;
175           int index;
176
177           for (int j = 0; j < varList.size(); j++) {
178             stringIdent = (String) varList.get(j);
179             len = stringIdent.length();
180             value = (PHPIdentifier) fIdentifierMap.get(stringIdent);
181             if (value != null) {
182               String obfuscatedIdentifier = value.getIdentifier();
183               if (obfuscatedIdentifier == null) {
184                 replacement = "$v" + Integer.toString(fCounter);
185                 value.setIdentifier("$v" + Integer.toString(fCounter++));
186               } else {
187                 replacement = obfuscatedIdentifier;
188               }
189               //     System.out.println(hexString.toString());
190             } else {
191               replacement = stringIdent;
192             }
193             index = stringLiteral.indexOf(stringIdent);
194             if (index >= 0) {
195               if (index > 0 && stringLiteral.charAt(index-1)!='\\') {
196                 stringLiteral.replace(index, index + stringIdent.length(), replacement);
197               } else if (index==0) {
198                 stringLiteral.replace(index, index + stringIdent.length(), replacement);
199               }
200             }
201           }
202           buf.append(stringLiteral);
203           startPosition = fScanner.currentPosition;
204           getNextToken();
205         }
206         if (fToken == TokenNameMINUS_GREATER) { // i.e. $this->var_name
207           getNextToken();
208           if (fToken == TokenNameIdentifier) {
209             // assuming this is a dereferenced variable
210             identifier = new String(fScanner.getCurrentIdentifierSource());
211             lastPosition = fScanner.startPosition;
212             int len = lastPosition - startPosition;
213             buf.append(fScanner.source, startPosition, len);
214             value = (PHPIdentifier) fIdentifierMap.get("$" + identifier);
215             if (value != null && value.isVariable()) {
216               String obfuscatedIdentifier = value.getIdentifier();
217               if (obfuscatedIdentifier == null) {
218                 // note: don't place a $ before the identifier
219                 buf.append("v" + Integer.toString(fCounter));
220                 value.setIdentifier("$v" + Integer.toString(fCounter++));
221               } else {
222                 if (obfuscatedIdentifier.charAt(0) == '$') {
223                   buf.append(obfuscatedIdentifier.substring(1));
224                 } else {
225                   buf.append(obfuscatedIdentifier);
226                 }
227               }
228             } else {
229               buf.append(identifier);
230             }
231             startPosition = fScanner.currentPosition;
232             getNextToken();
233           }
234
235         } else {
236           getNextToken();
237         }
238       }
239       if (startPosition < fScanner.source.length) {
240         buf.append(fScanner.source, startPosition, fScanner.source.length - startPosition);
241       }
242       return true;
243     } catch (SyntaxError sytaxErr) {
244       // do nothing 
245     }
246
247     return false;
248   }
249
250   public File copy(File sourceFile, File targetDir) {
251     try {
252       File targetFile = new File(targetDir, getTargetName(sourceFile));
253       //      if (targetFile.exists())
254       //        if (targetFile.lastModified() >= sourceFile.lastModified())
255       //          return null;
256       synchronized (bytes) {
257         FileInputStream in = new FileInputStream(sourceFile);
258         FileOutputStream out = new FileOutputStream(targetFile);
259         for (int len = in.read(bytes); len != -1; len = in.read(bytes)) {
260           out.write(bytes, 0, len);
261         }
262         in.close();
263         out.close();
264       }
265       return targetFile;
266     } catch (IOException e) {
267       fConsole.write(e.toString());
268     }
269     return null;
270   }
271
272   /**
273    * Move one file.
274    * @param sourceFile the file to move
275    * @param targetDir the directory to copy the result to
276    * @return file or null if the file was ignored
277    */
278   public File move(File sourceFile, File targetDir) {
279
280     try {
281
282       String fileName = sourceFile.getAbsolutePath().toLowerCase();
283       if (fileName.endsWith(".php")
284         || fileName.endsWith(".php3")
285         || fileName.endsWith(".php4")
286         || fileName.endsWith(".phtml")
287         || fileName.endsWith(".inc")) {
288         StringBuffer buf = new StringBuffer();
289         long filelen = sourceFile.length();
290         char[] charArray = new char[(int) filelen];
291
292         BufferedReader br = new BufferedReader(new FileReader(sourceFile.getAbsolutePath()));
293         br.read(charArray, 0, (int) filelen);
294
295         //        int offset = 0;
296         //        String line;
297         //        while ((line = br.readLine()) != null) {
298         //          System.arraycopy(line.toCharArray(), 0, charArray, offset, line.length());
299         //          offset += line.length();
300         //        }
301         br.close();
302
303         fScanner.setSource(charArray);
304         fScanner.setPHPMode(false);
305         fToken = TokenNameEOF;
306         getNextToken();
307         buf = new StringBuffer();
308         if (!obfuscate(buf)) {
309           return copy(sourceFile, targetDir);
310         } else {
311           File targetFile = new File(targetDir, getTargetName(sourceFile));
312           BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile));
313           bw.write(buf.toString());
314           bw.close();
315           return targetFile;
316         }
317         
318       } else {
319         return copy(sourceFile, targetDir);
320       }
321
322     } catch (IOException e) {
323       fConsole.write(e.toString());
324     }
325     return null;
326   }
327 }