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 @SuppressWarnings({"removal"}) 51 final class PropMap implements SortedMap<String, String> { 52 private final TreeMap<String, String> theMap = new TreeMap<>();; 53 54 // Override: 55 public String put(String key, String value) { 56 String oldValue = theMap.put(key, value); 57 return oldValue; 58 } 59 60 // All this other stuff is private to the current package. 61 // Outide clients of Pack200 do not need to use it; they can 62 // get by with generic SortedMap functionality. 63 private static Map<String, String> defaultProps; 64 static { 65 Properties props = new Properties(); 66 67 // Allow implementation selected via -Dpack.disable.native=true 68 String propValue = getPropertyValue(Utils.DEBUG_DISABLE_NATIVE, "false"); 69 props.put(Utils.DEBUG_DISABLE_NATIVE, 70 String.valueOf(Boolean.parseBoolean(propValue))); 71 72 // Set the DEBUG_VERBOSE from system 73 int verbose = 0; 74 try { 75 verbose = Integer.decode(getPropertyValue(Utils.DEBUG_VERBOSE, "0")); 76 } catch (NumberFormatException e) { 77 } 78 props.put(Utils.DEBUG_VERBOSE, String.valueOf(verbose)); 79 80 // The segment size is unlimited 81 props.put(Pack200.Packer.SEGMENT_LIMIT, "-1"); 82 83 // Preserve file ordering by default. 84 props.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.TRUE); 85 86 // Preserve all modification times by default. 87 props.put(Pack200.Packer.MODIFICATION_TIME, Pack200.Packer.KEEP); 88 89 // Preserve deflation hints by default. 90 props.put(Pack200.Packer.DEFLATE_HINT, Pack200.Packer.KEEP); 91 92 // Pass through files with unrecognized attributes by default. 93 props.put(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); 94 95 // Pass through files with unrecognized format by default, also 96 // allow system property to be set 97 props.put(Utils.CLASS_FORMAT_ERROR, 98 getPropertyValue(Utils.CLASS_FORMAT_ERROR, Pack200.Packer.PASS)); 99 100 // Default effort is 5, midway between 1 and 9. 101 props.put(Pack200.Packer.EFFORT, "5"); 102 103 // Define certain attribute layouts by default. 104 // Do this after the previous props are put in place, 105 // to allow override if necessary. 106 String propFile = "intrinsic.properties"; 107 108 PrivilegedAction<InputStream> pa = 109 () -> PackerImpl.class.getResourceAsStream(propFile); 110 try (InputStream propStr = AccessController.doPrivileged(pa)) { 111 if (propStr == null) { 112 throw new RuntimeException(propFile + " cannot be loaded"); 113 } 114 props.load(propStr); 115 } catch (IOException ee) { 116 throw new RuntimeException(ee); 117 } 118 119 for (Map.Entry<Object, Object> e : props.entrySet()) { 120 String key = (String) e.getKey(); 121 String val = (String) e.getValue(); 122 if (key.startsWith("attribute.")) { 123 e.setValue(Attribute.normalizeLayoutString(val)); 124 } 125 } 126 127 @SuppressWarnings({"unchecked", "rawtypes"}) 128 HashMap<String, String> temp = new HashMap(props); // shrink to fit 129 defaultProps = temp; 130 } 131 132 private static String getPropertyValue(String key, String defaultValue) { 133 PrivilegedAction<String> pa = () -> System.getProperty(key); 134 String s = AccessController.doPrivileged(pa); 135 return s != null ? s : defaultValue; 136 } 137 138 PropMap() { 139 theMap.putAll(defaultProps); 140 } 141 142 // Return a view of this map which includes only properties 143 // that begin with the given prefix. This is easy because 144 // the map is sorted, and has a subMap accessor. 145 SortedMap<String, String> prefixMap(String prefix) { 146 int len = prefix.length(); 147 if (len == 0) 148 return this; 149 char nextch = (char)(prefix.charAt(len-1) + 1); 150 String limit = prefix.substring(0, len-1)+nextch; 151 //System.out.println(prefix+" => "+subMap(prefix, limit)); 152 return subMap(prefix, limit); 153 } 154 155 String getProperty(String s) { 156 return get(s); 157 } 158 String getProperty(String s, String defaultVal) { 159 String val = getProperty(s); 160 if (val == null) 161 return defaultVal; 162 return val; 163 } 164 String setProperty(String s, String val) { 165 return put(s, val); 166 } 167 168 // Get sequence of props for "prefix", and "prefix.*". 169 List<String> getProperties(String prefix) { 170 Collection<String> values = prefixMap(prefix).values(); 171 List<String> res = new ArrayList<>(values.size()); 172 res.addAll(values); 173 while (res.remove(null)); 174 return res; 175 } 176 177 private boolean toBoolean(String val) { 178 return Boolean.valueOf(val).booleanValue(); 179 } 180 boolean getBoolean(String s) { 181 return toBoolean(getProperty(s)); 182 } 183 boolean setBoolean(String s, boolean val) { 184 return toBoolean(setProperty(s, String.valueOf(val))); 185 } 186 int toInteger(String val) { 187 return toInteger(val, 0); 188 } 189 int toInteger(String val, int def) { 190 if (val == null) return def; 191 if (Pack200.Packer.TRUE.equals(val)) return 1; 192 if (Pack200.Packer.FALSE.equals(val)) return 0; 193 return Integer.parseInt(val); 194 } 195 int getInteger(String s, int def) { 196 return toInteger(getProperty(s), def); 197 } 198 int getInteger(String s) { 199 return toInteger(getProperty(s)); 200 } 201 int setInteger(String s, int val) { 202 return toInteger(setProperty(s, String.valueOf(val))); 203 } 204 205 long toLong(String val) { 206 try { 207 return val == null ? 0 : Long.parseLong(val); 208 } catch (java.lang.NumberFormatException nfe) { 209 throw new IllegalArgumentException("Invalid value"); 210 } 211 } 212 long getLong(String s) { 213 return toLong(getProperty(s)); 214 } 215 long setLong(String s, long val) { 216 return toLong(setProperty(s, String.valueOf(val))); 217 } 218 219 int getTime(String s) { 220 String sval = getProperty(s, "0"); 221 if (Utils.NOW.equals(sval)) { 222 return (int)((System.currentTimeMillis()+500)/1000); 223 } 224 long lval = toLong(sval); 225 final long recentSecondCount = 1000000000; 226 227 if (lval < recentSecondCount*10 && !"0".equals(sval)) 228 Utils.log.warning("Supplied modtime appears to be seconds rather than milliseconds: "+sval); 229 230 return (int)((lval+500)/1000); 231 } 232 233 void list(PrintStream out) { 234 PrintWriter outw = new PrintWriter(out); 235 list(outw); 236 outw.flush(); 237 } 238 void list(PrintWriter out) { 239 out.println("#"+Utils.PACK_ZIP_ARCHIVE_MARKER_COMMENT+"["); 240 Set<Map.Entry<String, String>> defaults = defaultProps.entrySet(); 241 for (Map.Entry<String, String> e : theMap.entrySet()) { 242 if (defaults.contains(e)) continue; 243 out.println(" " + e.getKey() + " = " + e.getValue()); 244 } 245 out.println("#]"); 246 } 247 248 @Override 249 public int size() { 250 return theMap.size(); 251 } 252 253 @Override 254 public boolean isEmpty() { 255 return theMap.isEmpty(); 256 } 257 258 @Override 259 public boolean containsKey(Object key) { 260 return theMap.containsKey(key); 261 } 262 263 @Override 264 public boolean containsValue(Object value) { 265 return theMap.containsValue(value); 266 } 267 268 @Override 269 public String get(Object key) { 270 return theMap.get(key); 271 } 272 273 @Override 274 public String remove(Object key) { 275 return theMap.remove(key); 276 } 277 278 @Override 279 public void putAll(Map<? extends String, ? extends String> m) { 280 theMap.putAll(m); 281 } 282 283 @Override 284 public void clear() { 285 theMap.clear(); 286 } 287 288 @Override 289 public Set<String> keySet() { 290 return theMap.keySet(); 291 } 292 293 @Override 294 public Collection<String> values() { 295 return theMap.values(); 296 } 297 298 @Override 299 public Set<Map.Entry<String, String>> entrySet() { 300 return theMap.entrySet(); 301 } 302 303 @Override 304 public Comparator<? super String> comparator() { 305 return theMap.comparator(); 306 } 307 308 @Override 309 public SortedMap<String, String> subMap(String fromKey, String toKey) { 310 return theMap.subMap(fromKey, toKey); 311 } 312 313 @Override 314 public SortedMap<String, String> headMap(String toKey) { 315 return theMap.headMap(toKey); 316 } 317 318 @Override 319 public SortedMap<String, String> tailMap(String fromKey) { 320 return theMap.tailMap(fromKey); 321 } 322 323 @Override 324 public String firstKey() { 325 return theMap.firstKey(); 326 } 327 328 @Override 329 public String lastKey() { 330 return theMap.lastKey(); 331 } 332 }