1 /* 2 * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.java.util.jar.pack; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.PrintStream; 31 import java.io.PrintWriter; 32 import java.security.AccessController; 33 import java.security.PrivilegedAction; 34 import java.util.ArrayList; 35 import java.util.Collection; 36 import java.util.Comparator; 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.Map; 40 import java.util.Properties; 41 import java.util.Set; 42 import java.util.SortedMap; 43 import java.util.TreeMap; 44 import java.util.jar.Pack200; 45 46 /** 47 * Control block for publishing Pack200 options to the other classes. 48 */ 49 50 final class PropMap implements SortedMap<String, String> { 51 private final TreeMap<String, String> theMap = new TreeMap<>();; 52 53 // Override: 54 public String put(String key, String value) { 55 String oldValue = theMap.put(key, value); 56 return oldValue; 57 } 58 59 // All this other stuff is private to the current package. 60 // Outide clients of Pack200 do not need to use it; they can 61 // get by with generic SortedMap functionality. 62 private static Map<String, String> defaultProps; 63 static { 64 Properties props = new Properties(); 65 66 // Allow implementation selected via -Dpack.disable.native=true 67 String propValue = getPropertyValue(Utils.DEBUG_DISABLE_NATIVE, "false"); 68 props.put(Utils.DEBUG_DISABLE_NATIVE, 69 String.valueOf(Boolean.parseBoolean(propValue))); 70 71 // Set the DEBUG_VERBOSE from system 72 int verbose = 0; 73 try { 74 verbose = Integer.decode(getPropertyValue(Utils.DEBUG_VERBOSE, "0")); 75 } catch (NumberFormatException e) { 76 } 77 props.put(Utils.DEBUG_VERBOSE, String.valueOf(verbose)); 78 79 // The segment size is unlimited 80 props.put(Pack200.Packer.SEGMENT_LIMIT, "-1"); 81 82 // Preserve file ordering by default. 83 props.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.TRUE); 84 85 // Preserve all modification times by default. 86 props.put(Pack200.Packer.MODIFICATION_TIME, Pack200.Packer.KEEP); 87 88 // Preserve deflation hints by default. 89 props.put(Pack200.Packer.DEFLATE_HINT, Pack200.Packer.KEEP); 90 91 // Pass through files with unrecognized attributes by default. 92 props.put(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); 93 94 // Pass through files with unrecognized format by default, also 95 // allow system property to be set 96 props.put(Utils.CLASS_FORMAT_ERROR, 97 getPropertyValue(Utils.CLASS_FORMAT_ERROR, Pack200.Packer.PASS)); 98 99 // Default effort is 5, midway between 1 and 9. 100 props.put(Pack200.Packer.EFFORT, "5"); 101 102 // Define certain attribute layouts by default. 103 // Do this after the previous props are put in place, 104 // to allow override if necessary. 105 String propFile = "intrinsic.properties"; 106 107 PrivilegedAction<InputStream> pa = 108 () -> PackerImpl.class.getResourceAsStream(propFile); 109 try (InputStream propStr = AccessController.doPrivileged(pa)) { 110 if (propStr == null) { 111 throw new RuntimeException(propFile + " cannot be loaded"); 112 } 113 props.load(propStr); 114 } catch (IOException ee) { 115 throw new RuntimeException(ee); 116 } 117 118 for (Map.Entry<Object, Object> e : props.entrySet()) { 119 String key = (String) e.getKey(); 120 String val = (String) e.getValue(); 121 if (key.startsWith("attribute.")) { 122 e.setValue(Attribute.normalizeLayoutString(val)); 123 } 124 } 125 126 @SuppressWarnings({"unchecked", "rawtypes"}) 127 HashMap<String, String> temp = new HashMap(props); // shrink to fit 128 defaultProps = temp; 129 } 130 131 private static String getPropertyValue(String key, String defaultValue) { 132 PrivilegedAction<String> pa = () -> System.getProperty(key); 133 String s = AccessController.doPrivileged(pa); 134 return s != null ? s : defaultValue; 135 } 136 137 PropMap() { 138 theMap.putAll(defaultProps); 139 } 140 141 // Return a view of this map which includes only properties 142 // that begin with the given prefix. This is easy because 143 // the map is sorted, and has a subMap accessor. 144 SortedMap<String, String> prefixMap(String prefix) { 145 int len = prefix.length(); 146 if (len == 0) 147 return this; 148 char nextch = (char)(prefix.charAt(len-1) + 1); 149 String limit = prefix.substring(0, len-1)+nextch; 150 //System.out.println(prefix+" => "+subMap(prefix, limit)); 151 return subMap(prefix, limit); 152 } 153 154 String getProperty(String s) { 155 return get(s); 156 } 157 String getProperty(String s, String defaultVal) { 158 String val = getProperty(s); 159 if (val == null) 160 return defaultVal; 161 return val; 162 } 163 String setProperty(String s, String val) { 164 return put(s, val); 165 } 166 167 // Get sequence of props for "prefix", and "prefix.*". 168 List<String> getProperties(String prefix) { 169 Collection<String> values = prefixMap(prefix).values(); 170 List<String> res = new ArrayList<>(values.size()); 171 res.addAll(values); 172 while (res.remove(null)); 173 return res; 174 } 175 176 private boolean toBoolean(String val) { 177 return Boolean.valueOf(val).booleanValue(); 178 } 179 boolean getBoolean(String s) { 180 return toBoolean(getProperty(s)); 181 } 182 boolean setBoolean(String s, boolean val) { 183 return toBoolean(setProperty(s, String.valueOf(val))); 184 } 185 int toInteger(String val) { 186 return toInteger(val, 0); 187 } 188 int toInteger(String val, int def) { 189 if (val == null) return def; 190 if (Pack200.Packer.TRUE.equals(val)) return 1; 191 if (Pack200.Packer.FALSE.equals(val)) return 0; 192 return Integer.parseInt(val); 193 } 194 int getInteger(String s, int def) { 195 return toInteger(getProperty(s), def); 196 } 197 int getInteger(String s) { 198 return toInteger(getProperty(s)); 199 } 200 int setInteger(String s, int val) { 201 return toInteger(setProperty(s, String.valueOf(val))); 202 } 203 204 long toLong(String val) { 205 try { 206 return val == null ? 0 : Long.parseLong(val); 207 } catch (java.lang.NumberFormatException nfe) { 208 throw new IllegalArgumentException("Invalid value"); 209 } 210 } 211 long getLong(String s) { 212 return toLong(getProperty(s)); 213 } 214 long setLong(String s, long val) { 215 return toLong(setProperty(s, String.valueOf(val))); 216 } 217 218 int getTime(String s) { 219 String sval = getProperty(s, "0"); 220 if (Utils.NOW.equals(sval)) { 221 return (int)((System.currentTimeMillis()+500)/1000); 222 } 223 long lval = toLong(sval); 224 final long recentSecondCount = 1000000000; 225 226 if (lval < recentSecondCount*10 && !"0".equals(sval)) 227 Utils.log.warning("Supplied modtime appears to be seconds rather than milliseconds: "+sval); 228 229 return (int)((lval+500)/1000); 230 } 231 232 void list(PrintStream out) { 233 PrintWriter outw = new PrintWriter(out); 234 list(outw); 235 outw.flush(); 236 } 237 void list(PrintWriter out) { 238 out.println("#"+Utils.PACK_ZIP_ARCHIVE_MARKER_COMMENT+"["); 239 Set<Map.Entry<String, String>> defaults = defaultProps.entrySet(); 240 for (Map.Entry<String, String> e : theMap.entrySet()) { 241 if (defaults.contains(e)) continue; 242 out.println(" " + e.getKey() + " = " + e.getValue()); 243 } 244 out.println("#]"); 245 } 246 247 @Override 248 public int size() { 249 return theMap.size(); 250 } 251 252 @Override 253 public boolean isEmpty() { 254 return theMap.isEmpty(); 255 } 256 257 @Override 258 public boolean containsKey(Object key) { 259 return theMap.containsKey(key); 260 } 261 262 @Override 263 public boolean containsValue(Object value) { 264 return theMap.containsValue(value); 265 } 266 267 @Override 268 public String get(Object key) { 269 return theMap.get(key); 270 } 271 272 @Override 273 public String remove(Object key) { 274 return theMap.remove(key); 275 } 276 277 @Override 278 public void putAll(Map<? extends String, ? extends String> m) { 279 theMap.putAll(m); 280 } 281 282 @Override 283 public void clear() { 284 theMap.clear(); 285 } 286 287 @Override 288 public Set<String> keySet() { 289 return theMap.keySet(); 290 } 291 292 @Override 293 public Collection<String> values() { 294 return theMap.values(); 295 } 296 297 @Override 298 public Set<Map.Entry<String, String>> entrySet() { 299 return theMap.entrySet(); 300 } 301 302 @Override 303 public Comparator<? super String> comparator() { 304 return theMap.comparator(); 305 } 306 307 @Override 308 public SortedMap<String, String> subMap(String fromKey, String toKey) { 309 return theMap.subMap(fromKey, toKey); 310 } 311 312 @Override 313 public SortedMap<String, String> headMap(String toKey) { 314 return theMap.headMap(toKey); 315 } 316 317 @Override 318 public SortedMap<String, String> tailMap(String fromKey) { 319 return theMap.tailMap(fromKey); 320 } 321 322 @Override 323 public String firstKey() { 324 return theMap.firstKey(); 325 } 326 327 @Override 328 public String lastKey() { 329 return theMap.lastKey(); 330 } 331 }