Changes:
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / obfuscator / ObfuscatorPass2Exporter.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpeclipse.obfuscator;
12
13 import java.io.BufferedInputStream;
14 import java.io.BufferedWriter;
15 import java.io.File;
16 import java.io.FileNotFoundException;
17 import java.io.FileOutputStream;
18 import java.io.FileWriter;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23
24 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
25 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
26 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
27 import net.sourceforge.phpdt.internal.compiler.parser.SyntaxError;
28 import net.sourceforge.phpdt.internal.compiler.util.Util;
29 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
30 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
31
32 import org.eclipse.core.resources.IContainer;
33 import org.eclipse.core.resources.IFile;
34 import org.eclipse.core.resources.IResource;
35 import org.eclipse.core.runtime.CoreException;
36 import org.eclipse.core.runtime.IPath;
37 import org.eclipse.jface.preference.IPreferenceStore;
38
39 /**
40  * Helper class for exporting resources to the file system.
41  */
42 public class ObfuscatorPass2Exporter implements ITerminalSymbols {
43   private Scanner fScanner;
44   private int fToken;
45   private int fCounter;
46
47   protected HashMap fIdentifierMap;
48
49   public ObfuscatorPass2Exporter(Scanner scanner, HashMap identifierMap) {
50     fScanner = scanner;
51     fIdentifierMap = identifierMap;
52     fCounter = 0;
53   }
54   
55   /**
56         * gets the next token from input
57         */
58   private void getNextToken() {
59
60     try {
61       fToken = fScanner.getNextToken();
62       if (Scanner.DEBUG) {
63         int currentEndPosition = fScanner.getCurrentTokenEndPosition();
64         int currentStartPosition = fScanner.getCurrentTokenStartPosition();
65
66         System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
67         System.out.println(fScanner.toStringAction(fToken));
68       }
69       return;
70     } catch (InvalidInputException e) {
71
72     }
73     fToken = TokenNameERROR;
74   }
75
76   private boolean obfuscate(StringBuffer buf) {
77     char[] ident;
78     String identifier;
79     PHPIdentifier value;
80
81     int startPosition = 0;
82     int lastPosition = 0;
83
84     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
85     try {
86       while (fToken != TokenNameEOF && fToken != TokenNameERROR) {
87         if (fToken == TokenNameVariable) {
88           identifier = new String(fScanner.getCurrentIdentifierSource());
89           lastPosition = fScanner.startPosition;
90           int len = lastPosition - startPosition;
91           buf.append(fScanner.source, startPosition, len);
92           value = (PHPIdentifier) fIdentifierMap.get(identifier);
93           if (value != null) {
94             String obfuscatedIdentifier = value.getIdentifier();
95             if (obfuscatedIdentifier == null) {
96               buf.append("$v" + Integer.toString(fCounter));
97               value.setIdentifier("$v" + Integer.toString(fCounter++));
98             } else {
99               buf.append(obfuscatedIdentifier);
100             }
101             //     System.out.println(hexString.toString());
102           } else {
103             buf.append(identifier);
104           }
105           startPosition = fScanner.currentPosition;
106           getNextToken();
107         } else if (fToken == TokenNameIdentifier) {
108           identifier = new String(fScanner.getCurrentIdentifierSource());
109           lastPosition = fScanner.startPosition;
110           int len = lastPosition - startPosition;
111           buf.append(fScanner.source, startPosition, len);
112           value = (PHPIdentifier) fIdentifierMap.get(identifier);
113           if (value != null) {
114             String obfuscatedIdentifier = value.getIdentifier();
115             if (obfuscatedIdentifier == null) {
116               buf.append("_" + Integer.toString(fCounter));
117               value.setIdentifier("_" + Integer.toString(fCounter++));
118             } else {
119               buf.append(obfuscatedIdentifier);
120             }
121             //     System.out.println(hexString.toString());
122           } else {
123             buf.append(identifier);
124           }
125           startPosition = fScanner.currentPosition;
126           getNextToken();
127
128         } else if (fToken == TokenNameCOMMENT_LINE || fToken == TokenNameCOMMENT_BLOCK || fToken == TokenNameCOMMENT_PHPDOC) {
129           lastPosition = fScanner.startPosition;
130           buf.append(fScanner.source, startPosition, lastPosition - startPosition);
131           startPosition = fScanner.currentPosition;
132           getNextToken();
133         } else if (fToken == TokenNameStringLiteral) {
134           char currentCharacter;
135           int i = fScanner.startPosition;
136           ArrayList varList = new ArrayList();
137
138           lastPosition = fScanner.startPosition;
139           int len = lastPosition - startPosition;
140           buf.append(fScanner.source, startPosition, len);
141
142           while (i < fScanner.currentPosition) {
143             currentCharacter = fScanner.source[i++];
144             if (currentCharacter == '$' && fScanner.source[i - 2] != '\\') {
145               StringBuffer varName = new StringBuffer();
146               varName.append("$");
147               while (i < fScanner.currentPosition) {
148                 currentCharacter = fScanner.source[i++];
149                 if (!Scanner.isPHPIdentifierPart(currentCharacter)) {
150                   break; // while loop
151                 }
152                 varName.append(currentCharacter);
153               }
154               varList.add(varName.toString());
155             }
156           }
157           StringBuffer stringLiteral = new StringBuffer();
158           stringLiteral.append(fScanner.source, fScanner.startPosition, fScanner.currentPosition - fScanner.startPosition);
159           String stringIdent;
160           String replacement;
161           int index;
162
163           for (int j = 0; j < varList.size(); j++) {
164             stringIdent = (String) varList.get(j);
165             len = stringIdent.length();
166             value = (PHPIdentifier) fIdentifierMap.get(stringIdent);
167             if (value != null) {
168               String obfuscatedIdentifier = value.getIdentifier();
169               if (obfuscatedIdentifier == null) {
170                 replacement = "$v" + Integer.toString(fCounter);
171                 value.setIdentifier("$v" + Integer.toString(fCounter++));
172               } else {
173                 replacement = obfuscatedIdentifier;
174               }
175               //     System.out.println(hexString.toString());
176             } else {
177               replacement = stringIdent;
178             }
179             index = stringLiteral.indexOf(stringIdent);
180             if (index >= 0) {
181               if (index > 0 && stringLiteral.charAt(index - 1) != '\\') {
182                 stringLiteral.replace(index, index + stringIdent.length(), replacement);
183               } else if (index == 0) {
184                 stringLiteral.replace(index, index + stringIdent.length(), replacement);
185               }
186             }
187           }
188           buf.append(stringLiteral);
189           startPosition = fScanner.currentPosition;
190           getNextToken();
191         }
192         if (fToken == TokenNameMINUS_GREATER) { // i.e. $this->var_name
193           getNextToken();
194           if (fToken == TokenNameIdentifier) {
195             // assuming this is a dereferenced variable
196             identifier = new String(fScanner.getCurrentIdentifierSource());
197             lastPosition = fScanner.startPosition;
198             int len = lastPosition - startPosition;
199             buf.append(fScanner.source, startPosition, len);
200             value = (PHPIdentifier) fIdentifierMap.get("$" + identifier);
201             if (value != null && value.isVariable()) {
202               String obfuscatedIdentifier = value.getIdentifier();
203               if (obfuscatedIdentifier == null) {
204                 // note: don't place a $ before the identifier
205                 buf.append("v" + Integer.toString(fCounter));
206                 value.setIdentifier("$v" + Integer.toString(fCounter++));
207               } else {
208                 if (obfuscatedIdentifier.charAt(0) == '$') {
209                   buf.append(obfuscatedIdentifier.substring(1));
210                 } else {
211                   buf.append(obfuscatedIdentifier);
212                 }
213               }
214             } else {
215               buf.append(identifier);
216             }
217             startPosition = fScanner.currentPosition;
218             getNextToken();
219           }
220
221         } else {
222           getNextToken();
223         }
224       }
225       if (startPosition < fScanner.source.length) {
226         buf.append(fScanner.source, startPosition, fScanner.source.length - startPosition);
227       }
228       return true;
229     } catch (SyntaxError sytaxErr) {
230       // do nothing 
231     }
232
233     return false;
234   }
235   /**
236    *  Creates the specified file system directory at <code>destinationPath</code>.
237    *  This creates a new file system directory.
238    */
239   public void createFolder(IPath destinationPath) {
240     new File(destinationPath.toOSString()).mkdir();
241   }
242   /**
243    *  Writes the passed resource to the specified location recursively
244    */
245   public void write(IResource resource, IPath destinationPath) throws CoreException, IOException {
246     if (resource.getType() == IResource.FILE)
247       writeFile((IFile) resource, destinationPath);
248     else
249       writeChildren((IContainer) resource, destinationPath);
250   }
251   /**
252    *  Exports the passed container's children
253    */
254   protected void writeChildren(IContainer folder, IPath destinationPath) throws CoreException, IOException {
255     if (folder.isAccessible()) {
256       IResource[] children = folder.members();
257       for (int i = 0; i < children.length; i++) {
258         IResource child = children[i];
259         writeResource(child, destinationPath.append(child.getName()));
260       }
261     }
262   }
263   /**
264    *  Writes the passed file resource to the specified destination on the local
265    *  file system
266    */
267   protected void writeFile(IFile file, IPath destinationPath) throws IOException, CoreException {
268     if (PHPFileUtil.isPHPFile(file)) {
269       InputStream stream = null;
270       char[] charArray = null;
271       try {
272         stream = new BufferedInputStream(file.getContents());
273         charArray = Util.getInputStreamAsCharArray(stream, -1, null);
274       } catch (IOException e) {
275         return;
276       } finally {
277         try {
278           if (stream != null) {
279             stream.close();
280           }
281         } catch (IOException e) {
282         }
283       }
284
285       if (charArray == null) {
286         // TODO show error message 
287         return;
288       }
289
290       fScanner.setSource(charArray);
291       fScanner.setPHPMode(false);
292       fToken = TokenNameEOF;
293       getNextToken();
294
295       StringBuffer buf = new StringBuffer();
296       if (!obfuscate(buf)) {
297         copyFile(file, destinationPath);
298       } else {
299         //                              charArray = buf.toString().toCharArray();
300         //        File targetFile = new File(destinationPath.toOSString());
301         BufferedWriter bw = new BufferedWriter(new FileWriter(destinationPath.toOSString()));
302         bw.write(buf.toString());
303         bw.close();
304       }
305
306     } else {
307       copyFile(file, destinationPath);
308     }
309   }
310
311   private void copyFile(IFile file, IPath destinationPath) throws FileNotFoundException, CoreException, IOException {
312     FileOutputStream output = null;
313     InputStream contentStream = null;
314
315     try {
316       output = new FileOutputStream(destinationPath.toOSString());
317       contentStream = file.getContents(false);
318       int chunkSize = contentStream.available();
319       byte[] readBuffer = new byte[chunkSize];
320       int n = contentStream.read(readBuffer);
321
322       while (n > 0) {
323         output.write(readBuffer);
324         n = contentStream.read(readBuffer);
325       }
326     } finally {
327       if (output != null)
328         output.close();
329       if (contentStream != null)
330         contentStream.close();
331     }
332   }
333   /**
334    *  Writes the passed resource to the specified location recursively
335    */
336   protected void writeResource(IResource resource, IPath destinationPath) throws CoreException, IOException {
337     if (resource.getType() == IResource.FILE)
338       writeFile((IFile) resource, destinationPath);
339     else {
340       createFolder(destinationPath);
341       writeChildren((IContainer) resource, destinationPath);
342     }
343   }
344 }