001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.compress.harmony.pack200; 018 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.Iterator; 022import java.util.List; 023import java.util.Map; 024 025import org.objectweb.asm.Attribute; 026 027/** 028 * Utility class to manage the various options available for pack200 029 */ 030public class PackingOptions { 031 032 public static final String STRIP = "strip"; 033 public static final String ERROR = "error"; 034 public static final String PASS = "pass"; 035 public static final String KEEP = "keep"; 036 037 // All options are initially set to their defaults 038 private boolean gzip = true; 039 private boolean stripDebug = false; 040 private boolean keepFileOrder = true; 041 private long segmentLimit = 1000000L; 042 private int effort = 5; 043 private String deflateHint = KEEP; 044 private String modificationTime = KEEP; 045 private List passFiles; 046 private String unknownAttributeAction = PASS; 047 private Map classAttributeActions; 048 private Map fieldAttributeActions; 049 private Map methodAttributeActions; 050 private Map codeAttributeActions; 051 private boolean verbose = false; 052 private String logFile; 053 054 private Attribute[] unknownAttributeTypes; 055 056 public boolean isGzip() { 057 return gzip; 058 } 059 060 public void setGzip(final boolean gzip) { 061 this.gzip = gzip; 062 } 063 064 public boolean isStripDebug() { 065 return stripDebug; 066 } 067 068 /** 069 * Set strip debug attributes. If true, all debug attributes (i.e. LineNumberTable, SourceFile, LocalVariableTable 070 * and LocalVariableTypeTable attributes) are stripped when reading the input class files and not included in the 071 * output archive. 072 * 073 * @param stripDebug If true, all debug attributes. 074 */ 075 public void setStripDebug(final boolean stripDebug) { 076 this.stripDebug = stripDebug; 077 } 078 079 public boolean isKeepFileOrder() { 080 return keepFileOrder; 081 } 082 083 public void setKeepFileOrder(final boolean keepFileOrder) { 084 this.keepFileOrder = keepFileOrder; 085 } 086 087 public long getSegmentLimit() { 088 return segmentLimit; 089 } 090 091 /** 092 * Set the segment limit (equivalent to -S command line option) 093 * 094 * @param segmentLimit - the limit in bytes 095 */ 096 public void setSegmentLimit(final long segmentLimit) { 097 this.segmentLimit = segmentLimit; 098 } 099 100 public int getEffort() { 101 return effort; 102 } 103 104 /** 105 * Sets the compression effort level (0-9, equivalent to -E command line option) 106 * 107 * @param effort the compression effort level, 0-9. 108 */ 109 public void setEffort(final int effort) { 110 this.effort = effort; 111 } 112 113 public String getDeflateHint() { 114 return deflateHint; 115 } 116 117 public boolean isKeepDeflateHint() { 118 return KEEP.equals(deflateHint); 119 } 120 121 public void setDeflateHint(final String deflateHint) { 122 if (!KEEP.equals(deflateHint) && !"true".equals(deflateHint) && !"false".equals(deflateHint)) { 123 throw new IllegalArgumentException( 124 "Bad argument: -H " + deflateHint + " ? deflate hint should be either true, false or keep (default)"); 125 } 126 this.deflateHint = deflateHint; 127 } 128 129 public String getModificationTime() { 130 return modificationTime; 131 } 132 133 public void setModificationTime(final String modificationTime) { 134 if (!KEEP.equals(modificationTime) && !"latest".equals(modificationTime)) { 135 throw new IllegalArgumentException("Bad argument: -m " + modificationTime 136 + " ? transmit modtimes should be either latest or keep (default)"); 137 } 138 this.modificationTime = modificationTime; 139 } 140 141 public boolean isPassFile(final String passFileName) { 142 if (passFiles != null) { 143 for (final Iterator iterator = passFiles.iterator(); iterator.hasNext();) { 144 String pass = (String) iterator.next(); 145 if (passFileName.equals(pass)) { 146 return true; 147 } 148 if (!pass.endsWith(".class")) { // a whole directory is 149 // passed 150 if (!pass.endsWith("/")) { 151 // Make sure we don't get any false positives (e.g. 152 // exclude "org/apache/harmony/pack" should not match 153 // files under "org/apache/harmony/pack200/") 154 pass = pass + "/"; 155 } 156 return passFileName.startsWith(pass); 157 } 158 } 159 } 160 return false; 161 } 162 163 /** 164 * Tell the compressor to pass the file with the given name, or if the name is a directory name all files under that 165 * directory will be passed. 166 * 167 * @param passFileName the file name 168 */ 169 public void addPassFile(String passFileName) { 170 if (passFiles == null) { 171 passFiles = new ArrayList(); 172 } 173 String fileSeparator = System.getProperty("file.separator"); 174 if (fileSeparator.equals("\\")) { 175 // Need to escape backslashes for replaceAll(), which uses regex 176 fileSeparator += "\\"; 177 } 178 passFileName = passFileName.replaceAll(fileSeparator, "/"); 179 passFiles.add(passFileName); 180 } 181 182 public void removePassFile(final String passFileName) { 183 passFiles.remove(passFileName); 184 } 185 186 public String getUnknownAttributeAction() { 187 return unknownAttributeAction; 188 } 189 190 /** 191 * Tell the compressor what to do if an unknown attribute is encountered 192 * 193 * @param unknownAttributeAction - the action to perform 194 */ 195 public void setUnknownAttributeAction(final String unknownAttributeAction) { 196 this.unknownAttributeAction = unknownAttributeAction; 197 if (!PASS.equals(unknownAttributeAction) && !ERROR.equals(unknownAttributeAction) 198 && !STRIP.equals(unknownAttributeAction)) { 199 throw new RuntimeException("Incorrect option for -U, " + unknownAttributeAction); 200 } 201 } 202 203 public void addClassAttributeAction(final String attributeName, final String action) { 204 if (classAttributeActions == null) { 205 classAttributeActions = new HashMap(); 206 } 207 classAttributeActions.put(attributeName, action); 208 } 209 210 public void addFieldAttributeAction(final String attributeName, final String action) { 211 if (fieldAttributeActions == null) { 212 fieldAttributeActions = new HashMap(); 213 } 214 fieldAttributeActions.put(attributeName, action); 215 } 216 217 public void addMethodAttributeAction(final String attributeName, final String action) { 218 if (methodAttributeActions == null) { 219 methodAttributeActions = new HashMap(); 220 } 221 methodAttributeActions.put(attributeName, action); 222 } 223 224 public void addCodeAttributeAction(final String attributeName, final String action) { 225 if (codeAttributeActions == null) { 226 codeAttributeActions = new HashMap(); 227 } 228 codeAttributeActions.put(attributeName, action); 229 } 230 231 public boolean isVerbose() { 232 return verbose; 233 } 234 235 public void setVerbose(final boolean verbose) { 236 this.verbose = verbose; 237 } 238 239 public void setQuiet(final boolean quiet) { 240 this.verbose = !quiet; 241 } 242 243 public String getLogFile() { 244 return logFile; 245 } 246 247 public void setLogFile(final String logFile) { 248 this.logFile = logFile; 249 } 250 251 private void addOrUpdateAttributeActions(final List prototypes, final Map attributeActions, final int tag) { 252 if ((attributeActions != null) && (attributeActions.size() > 0)) { 253 String name, action; 254 boolean prototypeExists; 255 NewAttribute newAttribute; 256 for (final Iterator iteratorI = attributeActions.keySet().iterator(); iteratorI.hasNext();) { 257 name = (String) iteratorI.next(); 258 action = (String) attributeActions.get(name); 259 prototypeExists = false; 260 for (final Iterator iteratorJ = prototypes.iterator(); iteratorJ.hasNext();) { 261 newAttribute = (NewAttribute) iteratorJ.next(); 262 if (newAttribute.type.equals(name)) { 263 // if the attribute exists, update its context 264 newAttribute.addContext(tag); 265 prototypeExists = true; 266 break; 267 } 268 } 269 // if no attribute is found, add a new attribute 270 if (!prototypeExists) { 271 if (ERROR.equals(action)) { 272 newAttribute = new NewAttribute.ErrorAttribute(name, tag); 273 } else if (STRIP.equals(action)) { 274 newAttribute = new NewAttribute.StripAttribute(name, tag); 275 } else if (PASS.equals(action)) { 276 newAttribute = new NewAttribute.PassAttribute(name, tag); 277 } else { 278 newAttribute = new NewAttribute(name, action, tag); 279 } 280 prototypes.add(newAttribute); 281 } 282 } 283 } 284 } 285 286 public Attribute[] getUnknownAttributePrototypes() { 287 if (unknownAttributeTypes == null) { 288 final List prototypes = new ArrayList(); 289 addOrUpdateAttributeActions(prototypes, classAttributeActions, AttributeDefinitionBands.CONTEXT_CLASS); 290 291 addOrUpdateAttributeActions(prototypes, methodAttributeActions, AttributeDefinitionBands.CONTEXT_METHOD); 292 293 addOrUpdateAttributeActions(prototypes, fieldAttributeActions, AttributeDefinitionBands.CONTEXT_FIELD); 294 295 addOrUpdateAttributeActions(prototypes, codeAttributeActions, AttributeDefinitionBands.CONTEXT_CODE); 296 297 unknownAttributeTypes = (Attribute[]) prototypes.toArray(new Attribute[0]); 298 } 299 return unknownAttributeTypes; 300 } 301 302 public String getUnknownClassAttributeAction(final String type) { 303 if (classAttributeActions == null) { 304 return unknownAttributeAction; 305 } 306 String action = (String) classAttributeActions.get(type); 307 if (action == null) { 308 action = unknownAttributeAction; 309 } 310 return action; 311 } 312 313 public String getUnknownMethodAttributeAction(final String type) { 314 if (methodAttributeActions == null) { 315 return unknownAttributeAction; 316 } 317 String action = (String) methodAttributeActions.get(type); 318 if (action == null) { 319 action = unknownAttributeAction; 320 } 321 return action; 322 } 323 324 public String getUnknownFieldAttributeAction(final String type) { 325 if (fieldAttributeActions == null) { 326 return unknownAttributeAction; 327 } 328 String action = (String) fieldAttributeActions.get(type); 329 if (action == null) { 330 action = unknownAttributeAction; 331 } 332 return action; 333 } 334 335 public String getUnknownCodeAttributeAction(final String type) { 336 if (codeAttributeActions == null) { 337 return unknownAttributeAction; 338 } 339 String action = (String) codeAttributeActions.get(type); 340 if (action == null) { 341 action = unknownAttributeAction; 342 } 343 return action; 344 } 345 346}