001 package org.shiftone.jrat.inject.process;
002
003
004 import org.shiftone.jrat.core.JRatException;
005 import org.shiftone.jrat.inject.InjectorOptions;
006 import org.shiftone.jrat.inject.bytecode.Transformer;
007 import org.shiftone.jrat.util.Assert;
008 import org.shiftone.jrat.util.VersionUtil;
009 import org.shiftone.jrat.util.io.IOUtil;
010 import org.shiftone.jrat.util.io.OpenInputStream;
011 import org.shiftone.jrat.util.log.Logger;
012 import org.shiftone.jrat.util.regex.CompositeMatcher;
013 import org.shiftone.jrat.util.regex.Matcher;
014
015 import java.io.File;
016 import java.io.IOException;
017 import java.io.InputStream;
018 import java.io.PrintStream;
019 import java.util.zip.Deflater;
020 import java.util.zip.ZipEntry;
021 import java.util.zip.ZipInputStream;
022 import java.util.zip.ZipOutputStream;
023
024
025 /**
026 * @author jeff@shiftone.org (Jeff Drost)
027 */
028 public class ArchiveFileProcessor extends AbstractFileProcessor {
029
030 private static final Logger LOG = Logger.getLogger(ArchiveFileProcessor.class);
031 private static final Matcher EXTENTION_MATCHER =
032 CompositeMatcher.buildCompositeGlobMatcher("zip,jar,ear,war,sar,har");
033 private static final int BUFFER_SIZE = 1024 * 64;
034
035 protected void processFile(Transformer transformer, InjectorOptions options, File source, File target) {
036
037 LOG.debug("processFile " + source.getAbsolutePath() + " => " + target.getAbsolutePath());
038
039 ZipInputStream sourceStream = new ZipInputStream(IOUtil.openInputStream(source, BUFFER_SIZE));
040 ZipOutputStream targetStream = new ZipOutputStream(IOUtil.openOutputStream(target, BUFFER_SIZE));
041
042 targetStream.setLevel(Deflater.BEST_SPEED);
043
044 try {
045 processStreams(transformer, options, sourceStream, targetStream);
046 }
047 catch (Exception e) {
048 throw new JRatException("error injecting " + source.getAbsoluteFile() + " => "
049 + target.getAbsolutePath(), e);
050 }
051 finally {
052 IOUtil.close(sourceStream);
053 IOUtil.close(targetStream);
054 }
055 }
056
057
058 protected boolean processStreams(
059 Transformer transformer, InjectorOptions options, ZipInputStream sourceStream, ZipOutputStream targetStream)
060 throws Exception {
061
062 Assert.assertNotNull("transformer", transformer);
063
064 ZipEntry inEntry = null;
065 ZipEntry outEntry = null;
066 InputStream entryInputStream;
067
068 addReadmeCommentFile(targetStream);
069
070 while ((inEntry = sourceStream.getNextEntry()) != null) {
071 outEntry = new ZipEntry(inEntry.getName());
072 entryInputStream = new OpenInputStream(sourceStream);
073
074 targetStream.putNextEntry(outEntry);
075
076 String ext = getNormalizedExtention(inEntry);
077
078 if (isArchiveExtention(ext)) {
079 LOG.info("Entering nested archive : " + outEntry.getName());
080
081 ZipInputStream nestedSourceStream = new ZipInputStream(entryInputStream);
082 ZipOutputStream nestedTargetStream = new ZipOutputStream(targetStream);
083
084 processStreams(transformer, options, nestedSourceStream, nestedTargetStream);
085 nestedTargetStream.finish(); // this line seems important...
086
087 // :)
088 } else if (isClassExtention(ext)) {
089 LOG.debug("injecting " + inEntry.getName());
090
091 byte[] transformedClass = transformer.inject(entryInputStream, inEntry.getName(), options);
092
093 targetStream.write(transformedClass);
094 } else {
095 LOG.debug("copying " + inEntry.getName());
096 IOUtil.copy(entryInputStream, targetStream);
097 }
098
099 targetStream.closeEntry();
100 }
101
102 return true;
103 }
104
105
106 private void addReadmeCommentFile(ZipOutputStream zipOutputStream) {
107
108 ZipEntry entry = new ZipEntry("_READ_ME.JRAT");
109
110 try {
111 zipOutputStream.putNextEntry(entry);
112
113 PrintStream printStream = new PrintStream(zipOutputStream);
114
115 printStream.println("# This Archive file was injected by");
116 printStream.println("# Shiftone JRat the Java Runtime Analysis Toolkit");
117 printStream.println("# For more information, visit http://jrat.sourceforge.net");
118 printStream.println("#\tVersion : " + VersionUtil.getVersion());
119 printStream.println("#\tBuilt On : " + VersionUtil.getBuiltOn());
120 printStream.println("#\tBuilt By : " + VersionUtil.getBuiltBy());
121 printStream.println();
122 printStream.println();
123 printStream.println();
124 printStream.println("# the following system properties were present during injection");
125 printStream.flush();
126 System.getProperties().store(zipOutputStream, null);
127 zipOutputStream.closeEntry();
128 }
129 catch (IOException e) {
130 throw new JRatException("unable to add comment file to archive", e);
131 }
132 }
133
134
135 private String getNormalizedExtention(ZipEntry entry) {
136 return IOUtil.getExtention(entry.getName());
137 }
138
139
140 public static boolean isArchiveExtention(String ext) {
141 return EXTENTION_MATCHER.isMatch(ext);
142 }
143
144
145 public boolean isClassExtention(String ext) {
146 return (ext != null) && (ext.equals("class"));
147 }
148 }