1
25
26
54
55 package java.lang;
56
57 import java.io.*;
58 import java.util.*;
59
60
61 final class ProcessEnvironment
62 {
63 private static final HashMap<Variable,Value> theEnvironment;
64 private static final Map<String,String> theUnmodifiableEnvironment;
65 static final int MIN_NAME_LENGTH = 0;
66
67 static {
68
69
70 byte[][] environ = environ();
71 theEnvironment = new HashMap<>(environ.length/2 + 3);
72
73
74 for (int i = environ.length-1; i > 0; i-=2)
75 theEnvironment.put(Variable.valueOf(environ[i-1]),
76 Value.valueOf(environ[i]));
77
78 theUnmodifiableEnvironment
79 = Collections.unmodifiableMap
80 (new StringEnvironment(theEnvironment));
81 }
82
83
84 static String getenv(String name) {
85 return theUnmodifiableEnvironment.get(name);
86 }
87
88
89 static Map<String,String> getenv() {
90 return theUnmodifiableEnvironment;
91 }
92
93
94 @SuppressWarnings("unchecked")
95 static Map<String,String> environment() {
96 return new StringEnvironment
97 ((Map<Variable,Value>)(theEnvironment.clone()));
98 }
99
100
101 static Map<String,String> emptyEnvironment(int capacity) {
102 return new StringEnvironment(new HashMap<>(capacity));
103 }
104
105 private static native byte[][] environ();
106
107
108 private ProcessEnvironment() {}
109
110
111 private static void validateVariable(String name) {
112 if (name.indexOf('=') != -1 ||
113 name.indexOf('\u0000') != -1)
114 throw new IllegalArgumentException
115 ("Invalid environment variable name: \"" + name + "\"");
116 }
117
118
119 private static void validateValue(String value) {
120 if (value.indexOf('\u0000') != -1)
121 throw new IllegalArgumentException
122 ("Invalid environment variable value: \"" + value + "\"");
123 }
124
125
126
127 private abstract static class ExternalData {
128 protected final String str;
129 protected final byte[] bytes;
130
131 protected ExternalData(String str, byte[] bytes) {
132 this.str = str;
133 this.bytes = bytes;
134 }
135
136 public byte[] getBytes() {
137 return bytes;
138 }
139
140 public String toString() {
141 return str;
142 }
143
144 public boolean equals(Object o) {
145 return o instanceof ExternalData
146 && arrayEquals(getBytes(), ((ExternalData) o).getBytes());
147 }
148
149 public int hashCode() {
150 return arrayHash(getBytes());
151 }
152 }
153
154 private static class Variable
155 extends ExternalData implements Comparable<Variable>
156 {
157 protected Variable(String str, byte[] bytes) {
158 super(str, bytes);
159 }
160
161 public static Variable valueOfQueryOnly(Object str) {
162 return valueOfQueryOnly((String) str);
163 }
164
165 public static Variable valueOfQueryOnly(String str) {
166 return new Variable(str, str.getBytes());
167 }
168
169 public static Variable valueOf(String str) {
170 validateVariable(str);
171 return valueOfQueryOnly(str);
172 }
173
174 public static Variable valueOf(byte[] bytes) {
175 return new Variable(new String(bytes), bytes);
176 }
177
178 public int compareTo(Variable variable) {
179 return arrayCompare(getBytes(), variable.getBytes());
180 }
181
182 public boolean equals(Object o) {
183 return o instanceof Variable && super.equals(o);
184 }
185 }
186
187 private static class Value
188 extends ExternalData implements Comparable<Value>
189 {
190 protected Value(String str, byte[] bytes) {
191 super(str, bytes);
192 }
193
194 public static Value valueOfQueryOnly(Object str) {
195 return valueOfQueryOnly((String) str);
196 }
197
198 public static Value valueOfQueryOnly(String str) {
199 return new Value(str, str.getBytes());
200 }
201
202 public static Value valueOf(String str) {
203 validateValue(str);
204 return valueOfQueryOnly(str);
205 }
206
207 public static Value valueOf(byte[] bytes) {
208 return new Value(new String(bytes), bytes);
209 }
210
211 public int compareTo(Value value) {
212 return arrayCompare(getBytes(), value.getBytes());
213 }
214
215 public boolean equals(Object o) {
216 return o instanceof Value && super.equals(o);
217 }
218 }
219
220
221 private static class StringEnvironment
222 extends AbstractMap<String,String>
223 {
224 private Map<Variable,Value> m;
225 private static String toString(Value v) {
226 return v == null ? null : v.toString();
227 }
228 public StringEnvironment(Map<Variable,Value> m) {this.m = m;}
229 public int size() {return m.size();}
230 public boolean isEmpty() {return m.isEmpty();}
231 public void clear() { m.clear();}
232 public boolean containsKey(Object key) {
233 return m.containsKey(Variable.valueOfQueryOnly(key));
234 }
235 public boolean containsValue(Object value) {
236 return m.containsValue(Value.valueOfQueryOnly(value));
237 }
238 public String get(Object key) {
239 return toString(m.get(Variable.valueOfQueryOnly(key)));
240 }
241 public String put(String key, String value) {
242 return toString(m.put(Variable.valueOf(key),
243 Value.valueOf(value)));
244 }
245 public String remove(Object key) {
246 return toString(m.remove(Variable.valueOfQueryOnly(key)));
247 }
248 public Set<String> keySet() {
249 return new StringKeySet(m.keySet());
250 }
251 public Set<Map.Entry<String,String>> entrySet() {
252 return new StringEntrySet(m.entrySet());
253 }
254 public Collection<String> values() {
255 return new StringValues(m.values());
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270 public byte[] toEnvironmentBlock(int[]envc) {
271 int count = m.size() * 2;
272 for (Map.Entry<Variable,Value> entry : m.entrySet()) {
273 count += entry.getKey().getBytes().length;
274 count += entry.getValue().getBytes().length;
275 }
276
277 byte[] block = new byte[count];
278
279 int i = 0;
280 for (Map.Entry<Variable,Value> entry : m.entrySet()) {
281 byte[] key = entry.getKey ().getBytes();
282 byte[] value = entry.getValue().getBytes();
283 System.arraycopy(key, 0, block, i, key.length);
284 i+=key.length;
285 block[i++] = (byte) '=';
286 System.arraycopy(value, 0, block, i, value.length);
287 i+=value.length + 1;
288
289
290 }
291 envc[0] = m.size();
292 return block;
293 }
294 }
295
296 static byte[] toEnvironmentBlock(Map<String,String> map, int[]envc) {
297 return map == null ? null :
298 ((StringEnvironment)map).toEnvironmentBlock(envc);
299 }
300
301
302 private static class StringEntry
303 implements Map.Entry<String,String>
304 {
305 private final Map.Entry<Variable,Value> e;
306 public StringEntry(Map.Entry<Variable,Value> e) {this.e = e;}
307 public String getKey() {return e.getKey().toString();}
308 public String getValue() {return e.getValue().toString();}
309 public String setValue(String newValue) {
310 return e.setValue(Value.valueOf(newValue)).toString();
311 }
312 public String toString() {return getKey() + "=" + getValue();}
313 public boolean equals(Object o) {
314 return o instanceof StringEntry
315 && e.equals(((StringEntry)o).e);
316 }
317 public int hashCode() {return e.hashCode();}
318 }
319
320 private static class StringEntrySet
321 extends AbstractSet<Map.Entry<String,String>>
322 {
323 private final Set<Map.Entry<Variable,Value>> s;
324 public StringEntrySet(Set<Map.Entry<Variable,Value>> s) {this.s = s;}
325 public int size() {return s.size();}
326 public boolean isEmpty() {return s.isEmpty();}
327 public void clear() { s.clear();}
328 public Iterator<Map.Entry<String,String>> iterator() {
329 return new Iterator<Map.Entry<String,String>>() {
330 Iterator<Map.Entry<Variable,Value>> i = s.iterator();
331 public boolean hasNext() {return i.hasNext();}
332 public Map.Entry<String,String> next() {
333 return new StringEntry(i.next());
334 }
335 public void remove() {i.remove();}
336 };
337 }
338 private static Map.Entry<Variable,Value> vvEntry(final Object o) {
339 if (o instanceof StringEntry)
340 return ((StringEntry)o).e;
341 return new Map.Entry<Variable,Value>() {
342 public Variable getKey() {
343 return Variable.valueOfQueryOnly(((Map.Entry)o).getKey());
344 }
345 public Value getValue() {
346 return Value.valueOfQueryOnly(((Map.Entry)o).getValue());
347 }
348 public Value setValue(Value value) {
349 throw new UnsupportedOperationException();
350 }
351 };
352 }
353 public boolean contains(Object o) { return s.contains(vvEntry(o)); }
354 public boolean remove(Object o) { return s.remove(vvEntry(o)); }
355 public boolean equals(Object o) {
356 return o instanceof StringEntrySet
357 && s.equals(((StringEntrySet) o).s);
358 }
359 public int hashCode() {return s.hashCode();}
360 }
361
362 private static class StringValues
363 extends AbstractCollection<String>
364 {
365 private final Collection<Value> c;
366 public StringValues(Collection<Value> c) {this.c = c;}
367 public int size() {return c.size();}
368 public boolean isEmpty() {return c.isEmpty();}
369 public void clear() { c.clear();}
370 public Iterator<String> iterator() {
371 return new Iterator<String>() {
372 Iterator<Value> i = c.iterator();
373 public boolean hasNext() {return i.hasNext();}
374 public String next() {return i.next().toString();}
375 public void remove() {i.remove();}
376 };
377 }
378 public boolean contains(Object o) {
379 return c.contains(Value.valueOfQueryOnly(o));
380 }
381 public boolean remove(Object o) {
382 return c.remove(Value.valueOfQueryOnly(o));
383 }
384 public boolean equals(Object o) {
385 return o instanceof StringValues
386 && c.equals(((StringValues)o).c);
387 }
388 public int hashCode() {return c.hashCode();}
389 }
390
391 private static class StringKeySet extends AbstractSet<String> {
392 private final Set<Variable> s;
393 public StringKeySet(Set<Variable> s) {this.s = s;}
394 public int size() {return s.size();}
395 public boolean isEmpty() {return s.isEmpty();}
396 public void clear() { s.clear();}
397 public Iterator<String> iterator() {
398 return new Iterator<String>() {
399 Iterator<Variable> i = s.iterator();
400 public boolean hasNext() {return i.hasNext();}
401 public String next() {return i.next().toString();}
402 public void remove() { i.remove();}
403 };
404 }
405 public boolean contains(Object o) {
406 return s.contains(Variable.valueOfQueryOnly(o));
407 }
408 public boolean remove(Object o) {
409 return s.remove(Variable.valueOfQueryOnly(o));
410 }
411 }
412
413
414 private static int arrayCompare(byte[]x, byte[] y) {
415 int min = x.length < y.length ? x.length : y.length;
416 for (int i = 0; i < min; i++)
417 if (x[i] != y[i])
418 return x[i] - y[i];
419 return x.length - y.length;
420 }
421
422
423 private static boolean arrayEquals(byte[] x, byte[] y) {
424 if (x.length != y.length)
425 return false;
426 for (int i = 0; i < x.length; i++)
427 if (x[i] != y[i])
428 return false;
429 return true;
430 }
431
432
433 private static int arrayHash(byte[] x) {
434 int hash = 0;
435 for (int i = 0; i < x.length; i++)
436 hash = 31 * hash + x[i];
437 return hash;
438 }
439
440 }
441