rlm@10
|
1 /***
|
rlm@10
|
2 * ASM: a very small and fast Java bytecode manipulation framework
|
rlm@10
|
3 * Copyright (c) 2000-2005 INRIA, France Telecom
|
rlm@10
|
4 * All rights reserved.
|
rlm@10
|
5 *
|
rlm@10
|
6 * Redistribution and use in source and binary forms, with or without
|
rlm@10
|
7 * modification, are permitted provided that the following conditions
|
rlm@10
|
8 * are met:
|
rlm@10
|
9 * 1. Redistributions of source code must retain the above copyright
|
rlm@10
|
10 * notice, this list of conditions and the following disclaimer.
|
rlm@10
|
11 * 2. Redistributions in binary form must reproduce the above copyright
|
rlm@10
|
12 * notice, this list of conditions and the following disclaimer in the
|
rlm@10
|
13 * documentation and/or other materials provided with the distribution.
|
rlm@10
|
14 * 3. Neither the name of the copyright holders nor the names of its
|
rlm@10
|
15 * contributors may be used to endorse or promote products derived from
|
rlm@10
|
16 * this software without specific prior written permission.
|
rlm@10
|
17 *
|
rlm@10
|
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
rlm@10
|
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
rlm@10
|
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
rlm@10
|
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
rlm@10
|
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
rlm@10
|
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
rlm@10
|
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
rlm@10
|
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
rlm@10
|
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
rlm@10
|
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
rlm@10
|
28 * THE POSSIBILITY OF SUCH DAMAGE.
|
rlm@10
|
29 */
|
rlm@10
|
30 package clojure.asm.commons;
|
rlm@10
|
31
|
rlm@10
|
32 import java.io.ByteArrayOutputStream;
|
rlm@10
|
33 import java.io.DataOutputStream;
|
rlm@10
|
34 import java.io.IOException;
|
rlm@10
|
35 import java.security.MessageDigest;
|
rlm@10
|
36 import java.util.ArrayList;
|
rlm@10
|
37 import java.util.Arrays;
|
rlm@10
|
38 import java.util.Collection;
|
rlm@10
|
39
|
rlm@10
|
40 import clojure.asm.ClassAdapter;
|
rlm@10
|
41 import clojure.asm.ClassVisitor;
|
rlm@10
|
42 import clojure.asm.FieldVisitor;
|
rlm@10
|
43 import clojure.asm.MethodVisitor;
|
rlm@10
|
44 import clojure.asm.Opcodes;
|
rlm@10
|
45
|
rlm@10
|
46 /**
|
rlm@10
|
47 * A {@link ClassAdapter} that adds a serial version unique identifier to a
|
rlm@10
|
48 * class if missing. Here is typical usage of this class:
|
rlm@10
|
49 * <p/>
|
rlm@10
|
50 * <pre>
|
rlm@10
|
51 * ClassWriter cw = new ClassWriter(...);
|
rlm@10
|
52 * ClassVisitor sv = new SerialVersionUIDAdder(cw);
|
rlm@10
|
53 * ClassVisitor ca = new MyClassAdapter(sv);
|
rlm@10
|
54 * new ClassReader(orginalClass).accept(ca, false);
|
rlm@10
|
55 * </pre>
|
rlm@10
|
56 * <p/>
|
rlm@10
|
57 * The SVUID algorithm can be found <a href=
|
rlm@10
|
58 * "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html"
|
rlm@10
|
59 * >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>:
|
rlm@10
|
60 * <p/>
|
rlm@10
|
61 * <pre>
|
rlm@10
|
62 * The serialVersionUID is computed using the signature of a stream of bytes
|
rlm@10
|
63 * that reflect the class definition. The National Institute of Standards and
|
rlm@10
|
64 * Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
|
rlm@10
|
65 * signature for the stream. The first two 32-bit quantities are used to form a
|
rlm@10
|
66 * 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
|
rlm@10
|
67 * types to a sequence of bytes. The values input to the stream are defined by
|
rlm@10
|
68 * the Java Virtual Machine (VM) specification for classes.
|
rlm@10
|
69 * <p/>
|
rlm@10
|
70 * The sequence of items in the stream is as follows:
|
rlm@10
|
71 * <p/>
|
rlm@10
|
72 * 1. The class name written using UTF encoding.
|
rlm@10
|
73 * 2. The class modifiers written as a 32-bit integer.
|
rlm@10
|
74 * 3. The name of each interface sorted by name written using UTF encoding.
|
rlm@10
|
75 * 4. For each field of the class sorted by field name (except private static
|
rlm@10
|
76 * and private transient fields):
|
rlm@10
|
77 * 1. The name of the field in UTF encoding.
|
rlm@10
|
78 * 2. The modifiers of the field written as a 32-bit integer.
|
rlm@10
|
79 * 3. The descriptor of the field in UTF encoding
|
rlm@10
|
80 * 5. If a class initializer exists, write out the following:
|
rlm@10
|
81 * 1. The name of the method, <clinit>, in UTF encoding.
|
rlm@10
|
82 * 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
|
rlm@10
|
83 * written as a 32-bit integer.
|
rlm@10
|
84 * 3. The descriptor of the method, ()V, in UTF encoding.
|
rlm@10
|
85 * 6. For each non-private constructor sorted by method name and signature:
|
rlm@10
|
86 * 1. The name of the method, <init>, in UTF encoding.
|
rlm@10
|
87 * 2. The modifiers of the method written as a 32-bit integer.
|
rlm@10
|
88 * 3. The descriptor of the method in UTF encoding.
|
rlm@10
|
89 * 7. For each non-private method sorted by method name and signature:
|
rlm@10
|
90 * 1. The name of the method in UTF encoding.
|
rlm@10
|
91 * 2. The modifiers of the method written as a 32-bit integer.
|
rlm@10
|
92 * 3. The descriptor of the method in UTF encoding.
|
rlm@10
|
93 * 8. The SHA-1 algorithm is executed on the stream of bytes produced by
|
rlm@10
|
94 * DataOutputStream and produces five 32-bit values sha[0..4].
|
rlm@10
|
95 * <p/>
|
rlm@10
|
96 * 9. The hash value is assembled from the first and second 32-bit values of
|
rlm@10
|
97 * the SHA-1 message digest. If the result of the message digest, the five
|
rlm@10
|
98 * 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
|
rlm@10
|
99 * sha, the hash value would be computed as follows:
|
rlm@10
|
100 * <p/>
|
rlm@10
|
101 * long hash = ((sha[0] >>> 24) & 0xFF) |
|
rlm@10
|
102 * ((sha[0] >>> 16) & 0xFF) << 8 |
|
rlm@10
|
103 * ((sha[0] >>> 8) & 0xFF) << 16 |
|
rlm@10
|
104 * ((sha[0] >>> 0) & 0xFF) << 24 |
|
rlm@10
|
105 * ((sha[1] >>> 24) & 0xFF) << 32 |
|
rlm@10
|
106 * ((sha[1] >>> 16) & 0xFF) << 40 |
|
rlm@10
|
107 * ((sha[1] >>> 8) & 0xFF) << 48 |
|
rlm@10
|
108 * ((sha[1] >>> 0) & 0xFF) << 56;
|
rlm@10
|
109 * </pre>
|
rlm@10
|
110 *
|
rlm@10
|
111 * @author Rajendra Inamdar, Vishal Vishnoi
|
rlm@10
|
112 */
|
rlm@10
|
113 public class SerialVersionUIDAdder extends ClassAdapter{
|
rlm@10
|
114
|
rlm@10
|
115 /**
|
rlm@10
|
116 * Flag that indicates if we need to compute SVUID.
|
rlm@10
|
117 */
|
rlm@10
|
118 protected boolean computeSVUID;
|
rlm@10
|
119
|
rlm@10
|
120 /**
|
rlm@10
|
121 * Set to true if the class already has SVUID.
|
rlm@10
|
122 */
|
rlm@10
|
123 protected boolean hasSVUID;
|
rlm@10
|
124
|
rlm@10
|
125 /**
|
rlm@10
|
126 * Classes access flags.
|
rlm@10
|
127 */
|
rlm@10
|
128 protected int access;
|
rlm@10
|
129
|
rlm@10
|
130 /**
|
rlm@10
|
131 * Internal name of the class
|
rlm@10
|
132 */
|
rlm@10
|
133 protected String name;
|
rlm@10
|
134
|
rlm@10
|
135 /**
|
rlm@10
|
136 * Interfaces implemented by the class.
|
rlm@10
|
137 */
|
rlm@10
|
138 protected String[] interfaces;
|
rlm@10
|
139
|
rlm@10
|
140 /**
|
rlm@10
|
141 * Collection of fields. (except private static and private transient
|
rlm@10
|
142 * fields)
|
rlm@10
|
143 */
|
rlm@10
|
144 protected Collection svuidFields;
|
rlm@10
|
145
|
rlm@10
|
146 /**
|
rlm@10
|
147 * Set to true if the class has static initializer.
|
rlm@10
|
148 */
|
rlm@10
|
149 protected boolean hasStaticInitializer;
|
rlm@10
|
150
|
rlm@10
|
151 /**
|
rlm@10
|
152 * Collection of non-private constructors.
|
rlm@10
|
153 */
|
rlm@10
|
154 protected Collection svuidConstructors;
|
rlm@10
|
155
|
rlm@10
|
156 /**
|
rlm@10
|
157 * Collection of non-private methods.
|
rlm@10
|
158 */
|
rlm@10
|
159 protected Collection svuidMethods;
|
rlm@10
|
160
|
rlm@10
|
161 /**
|
rlm@10
|
162 * Creates a new {@link SerialVersionUIDAdder}.
|
rlm@10
|
163 *
|
rlm@10
|
164 * @param cv a {@link ClassVisitor} to which this visitor will delegate
|
rlm@10
|
165 * calls.
|
rlm@10
|
166 */
|
rlm@10
|
167 public SerialVersionUIDAdder(final ClassVisitor cv){
|
rlm@10
|
168 super(cv);
|
rlm@10
|
169 svuidFields = new ArrayList();
|
rlm@10
|
170 svuidConstructors = new ArrayList();
|
rlm@10
|
171 svuidMethods = new ArrayList();
|
rlm@10
|
172 }
|
rlm@10
|
173
|
rlm@10
|
174 // ------------------------------------------------------------------------
|
rlm@10
|
175 // Overriden methods
|
rlm@10
|
176 // ------------------------------------------------------------------------
|
rlm@10
|
177
|
rlm@10
|
178 /*
|
rlm@10
|
179 * Visit class header and get class name, access , and intefraces
|
rlm@10
|
180 * informatoin (step 1,2, and 3) for SVUID computation.
|
rlm@10
|
181 */
|
rlm@10
|
182
|
rlm@10
|
183 public void visit(
|
rlm@10
|
184 final int version,
|
rlm@10
|
185 final int access,
|
rlm@10
|
186 final String name,
|
rlm@10
|
187 final String signature,
|
rlm@10
|
188 final String superName,
|
rlm@10
|
189 final String[] interfaces){
|
rlm@10
|
190 computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0;
|
rlm@10
|
191
|
rlm@10
|
192 if(computeSVUID)
|
rlm@10
|
193 {
|
rlm@10
|
194 this.name = name;
|
rlm@10
|
195 this.access = access;
|
rlm@10
|
196 this.interfaces = interfaces;
|
rlm@10
|
197 }
|
rlm@10
|
198
|
rlm@10
|
199 super.visit(version, access, name, signature, superName, interfaces);
|
rlm@10
|
200 }
|
rlm@10
|
201
|
rlm@10
|
202 /*
|
rlm@10
|
203 * Visit the methods and get constructor and method information (step 5 and
|
rlm@10
|
204 * 7). Also determince if there is a class initializer (step 6).
|
rlm@10
|
205 */
|
rlm@10
|
206 public MethodVisitor visitMethod(
|
rlm@10
|
207 final int access,
|
rlm@10
|
208 final String name,
|
rlm@10
|
209 final String desc,
|
rlm@10
|
210 final String signature,
|
rlm@10
|
211 final String[] exceptions){
|
rlm@10
|
212 if(computeSVUID)
|
rlm@10
|
213 {
|
rlm@10
|
214 if(name.equals("<clinit>"))
|
rlm@10
|
215 {
|
rlm@10
|
216 hasStaticInitializer = true;
|
rlm@10
|
217 }
|
rlm@10
|
218 /*
|
rlm@10
|
219 * Remembers non private constructors and methods for SVUID
|
rlm@10
|
220 * computation For constructor and method modifiers, only the
|
rlm@10
|
221 * ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
|
rlm@10
|
222 * ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
|
rlm@10
|
223 * are used.
|
rlm@10
|
224 */
|
rlm@10
|
225 int mods = access
|
rlm@10
|
226 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
|
rlm@10
|
227 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
|
rlm@10
|
228 | Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
|
rlm@10
|
229 | Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
|
rlm@10
|
230
|
rlm@10
|
231 // all non private methods
|
rlm@10
|
232 if((access & Opcodes.ACC_PRIVATE) == 0)
|
rlm@10
|
233 {
|
rlm@10
|
234 if(name.equals("<init>"))
|
rlm@10
|
235 {
|
rlm@10
|
236 svuidConstructors.add(new Item(name, mods, desc));
|
rlm@10
|
237 }
|
rlm@10
|
238 else if(!name.equals("<clinit>"))
|
rlm@10
|
239 {
|
rlm@10
|
240 svuidMethods.add(new Item(name, mods, desc));
|
rlm@10
|
241 }
|
rlm@10
|
242 }
|
rlm@10
|
243 }
|
rlm@10
|
244
|
rlm@10
|
245 return cv.visitMethod(access, name, desc, signature, exceptions);
|
rlm@10
|
246 }
|
rlm@10
|
247
|
rlm@10
|
248 /*
|
rlm@10
|
249 * Gets class field information for step 4 of the alogrithm. Also determines
|
rlm@10
|
250 * if the class already has a SVUID.
|
rlm@10
|
251 */
|
rlm@10
|
252 public FieldVisitor visitField(
|
rlm@10
|
253 final int access,
|
rlm@10
|
254 final String name,
|
rlm@10
|
255 final String desc,
|
rlm@10
|
256 final String signature,
|
rlm@10
|
257 final Object value){
|
rlm@10
|
258 if(computeSVUID)
|
rlm@10
|
259 {
|
rlm@10
|
260 if(name.equals("serialVersionUID"))
|
rlm@10
|
261 {
|
rlm@10
|
262 // since the class already has SVUID, we won't be computing it.
|
rlm@10
|
263 computeSVUID = false;
|
rlm@10
|
264 hasSVUID = true;
|
rlm@10
|
265 }
|
rlm@10
|
266 /*
|
rlm@10
|
267 * Remember field for SVUID computation For field modifiers, only
|
rlm@10
|
268 * the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
|
rlm@10
|
269 * ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
|
rlm@10
|
270 * computing serialVersionUID values.
|
rlm@10
|
271 */
|
rlm@10
|
272 int mods = access
|
rlm@10
|
273 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
|
rlm@10
|
274 | Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
|
rlm@10
|
275 | Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
|
rlm@10
|
276
|
rlm@10
|
277 if((access & Opcodes.ACC_PRIVATE) == 0
|
rlm@10
|
278 || (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0)
|
rlm@10
|
279 {
|
rlm@10
|
280 svuidFields.add(new Item(name, mods, desc));
|
rlm@10
|
281 }
|
rlm@10
|
282 }
|
rlm@10
|
283
|
rlm@10
|
284 return super.visitField(access, name, desc, signature, value);
|
rlm@10
|
285 }
|
rlm@10
|
286
|
rlm@10
|
287 /*
|
rlm@10
|
288 * Add the SVUID if class doesn't have one
|
rlm@10
|
289 */
|
rlm@10
|
290 public void visitEnd(){
|
rlm@10
|
291 // compute SVUID and add it to the class
|
rlm@10
|
292 if(computeSVUID && !hasSVUID)
|
rlm@10
|
293 {
|
rlm@10
|
294 try
|
rlm@10
|
295 {
|
rlm@10
|
296 cv.visitField(Opcodes.ACC_FINAL + Opcodes.ACC_STATIC,
|
rlm@10
|
297 "serialVersionUID",
|
rlm@10
|
298 "J",
|
rlm@10
|
299 null,
|
rlm@10
|
300 new Long(computeSVUID()));
|
rlm@10
|
301 }
|
rlm@10
|
302 catch(Throwable e)
|
rlm@10
|
303 {
|
rlm@10
|
304 throw new RuntimeException("Error while computing SVUID for "
|
rlm@10
|
305 + name, e);
|
rlm@10
|
306 }
|
rlm@10
|
307 }
|
rlm@10
|
308
|
rlm@10
|
309 super.visitEnd();
|
rlm@10
|
310 }
|
rlm@10
|
311
|
rlm@10
|
312 // ------------------------------------------------------------------------
|
rlm@10
|
313 // Utility methods
|
rlm@10
|
314 // ------------------------------------------------------------------------
|
rlm@10
|
315
|
rlm@10
|
316 /**
|
rlm@10
|
317 * Returns the value of SVUID if the class doesn't have one already. Please
|
rlm@10
|
318 * note that 0 is returned if the class already has SVUID, thus use
|
rlm@10
|
319 * <code>isHasSVUID</code> to determine if the class already had an SVUID.
|
rlm@10
|
320 *
|
rlm@10
|
321 * @return Returns the serial version UID
|
rlm@10
|
322 * @throws IOException
|
rlm@10
|
323 */
|
rlm@10
|
324 protected long computeSVUID() throws IOException{
|
rlm@10
|
325 ByteArrayOutputStream bos = null;
|
rlm@10
|
326 DataOutputStream dos = null;
|
rlm@10
|
327 long svuid = 0;
|
rlm@10
|
328
|
rlm@10
|
329 try
|
rlm@10
|
330 {
|
rlm@10
|
331 bos = new ByteArrayOutputStream();
|
rlm@10
|
332 dos = new DataOutputStream(bos);
|
rlm@10
|
333
|
rlm@10
|
334 /*
|
rlm@10
|
335 * 1. The class name written using UTF encoding.
|
rlm@10
|
336 */
|
rlm@10
|
337 dos.writeUTF(name.replace('/', '.'));
|
rlm@10
|
338
|
rlm@10
|
339 /*
|
rlm@10
|
340 * 2. The class modifiers written as a 32-bit integer.
|
rlm@10
|
341 */
|
rlm@10
|
342 dos.writeInt(access
|
rlm@10
|
343 & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
|
rlm@10
|
344 | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
|
rlm@10
|
345
|
rlm@10
|
346 /*
|
rlm@10
|
347 * 3. The name of each interface sorted by name written using UTF
|
rlm@10
|
348 * encoding.
|
rlm@10
|
349 */
|
rlm@10
|
350 Arrays.sort(interfaces);
|
rlm@10
|
351 for(int i = 0; i < interfaces.length; i++)
|
rlm@10
|
352 {
|
rlm@10
|
353 dos.writeUTF(interfaces[i].replace('/', '.'));
|
rlm@10
|
354 }
|
rlm@10
|
355
|
rlm@10
|
356 /*
|
rlm@10
|
357 * 4. For each field of the class sorted by field name (except
|
rlm@10
|
358 * private static and private transient fields):
|
rlm@10
|
359 *
|
rlm@10
|
360 * 1. The name of the field in UTF encoding. 2. The modifiers of the
|
rlm@10
|
361 * field written as a 32-bit integer. 3. The descriptor of the field
|
rlm@10
|
362 * in UTF encoding
|
rlm@10
|
363 *
|
rlm@10
|
364 * Note that field signatutes are not dot separated. Method and
|
rlm@10
|
365 * constructor signatures are dot separated. Go figure...
|
rlm@10
|
366 */
|
rlm@10
|
367 writeItems(svuidFields, dos, false);
|
rlm@10
|
368
|
rlm@10
|
369 /*
|
rlm@10
|
370 * 5. If a class initializer exists, write out the following: 1. The
|
rlm@10
|
371 * name of the method, <clinit>, in UTF encoding. 2. The modifier of
|
rlm@10
|
372 * the method, java.lang.reflect.Modifier.STATIC, written as a
|
rlm@10
|
373 * 32-bit integer. 3. The descriptor of the method, ()V, in UTF
|
rlm@10
|
374 * encoding.
|
rlm@10
|
375 */
|
rlm@10
|
376 if(hasStaticInitializer)
|
rlm@10
|
377 {
|
rlm@10
|
378 dos.writeUTF("<clinit>");
|
rlm@10
|
379 dos.writeInt(Opcodes.ACC_STATIC);
|
rlm@10
|
380 dos.writeUTF("()V");
|
rlm@10
|
381 } // if..
|
rlm@10
|
382
|
rlm@10
|
383 /*
|
rlm@10
|
384 * 6. For each non-private constructor sorted by method name and
|
rlm@10
|
385 * signature: 1. The name of the method, <init>, in UTF encoding. 2.
|
rlm@10
|
386 * The modifiers of the method written as a 32-bit integer. 3. The
|
rlm@10
|
387 * descriptor of the method in UTF encoding.
|
rlm@10
|
388 */
|
rlm@10
|
389 writeItems(svuidConstructors, dos, true);
|
rlm@10
|
390
|
rlm@10
|
391 /*
|
rlm@10
|
392 * 7. For each non-private method sorted by method name and
|
rlm@10
|
393 * signature: 1. The name of the method in UTF encoding. 2. The
|
rlm@10
|
394 * modifiers of the method written as a 32-bit integer. 3. The
|
rlm@10
|
395 * descriptor of the method in UTF encoding.
|
rlm@10
|
396 */
|
rlm@10
|
397 writeItems(svuidMethods, dos, true);
|
rlm@10
|
398
|
rlm@10
|
399 dos.flush();
|
rlm@10
|
400
|
rlm@10
|
401 /*
|
rlm@10
|
402 * 8. The SHA-1 algorithm is executed on the stream of bytes
|
rlm@10
|
403 * produced by DataOutputStream and produces five 32-bit values
|
rlm@10
|
404 * sha[0..4].
|
rlm@10
|
405 */
|
rlm@10
|
406 byte[] hashBytes = computeSHAdigest(bos.toByteArray());
|
rlm@10
|
407
|
rlm@10
|
408 /*
|
rlm@10
|
409 * 9. The hash value is assembled from the first and second 32-bit
|
rlm@10
|
410 * values of the SHA-1 message digest. If the result of the message
|
rlm@10
|
411 * digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
|
rlm@10
|
412 * five int values named sha, the hash value would be computed as
|
rlm@10
|
413 * follows:
|
rlm@10
|
414 *
|
rlm@10
|
415 * long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF) <<
|
rlm@10
|
416 * 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
|
rlm@10
|
417 * 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
|
rlm@10
|
418 * 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
|
rlm@10
|
419 * 56;
|
rlm@10
|
420 */
|
rlm@10
|
421 for(int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--)
|
rlm@10
|
422 {
|
rlm@10
|
423 svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
|
rlm@10
|
424 }
|
rlm@10
|
425 }
|
rlm@10
|
426 finally
|
rlm@10
|
427 {
|
rlm@10
|
428 // close the stream (if open)
|
rlm@10
|
429 if(dos != null)
|
rlm@10
|
430 {
|
rlm@10
|
431 dos.close();
|
rlm@10
|
432 }
|
rlm@10
|
433 }
|
rlm@10
|
434
|
rlm@10
|
435 return svuid;
|
rlm@10
|
436 }
|
rlm@10
|
437
|
rlm@10
|
438 /**
|
rlm@10
|
439 * Returns the SHA-1 message digest of the given value.
|
rlm@10
|
440 *
|
rlm@10
|
441 * @param value the value whose SHA message digest must be computed.
|
rlm@10
|
442 * @return the SHA-1 message digest of the given value.
|
rlm@10
|
443 */
|
rlm@10
|
444 protected byte[] computeSHAdigest(final byte[] value){
|
rlm@10
|
445 try
|
rlm@10
|
446 {
|
rlm@10
|
447 return MessageDigest.getInstance("SHA").digest(value);
|
rlm@10
|
448 }
|
rlm@10
|
449 catch(Exception e)
|
rlm@10
|
450 {
|
rlm@10
|
451 throw new UnsupportedOperationException(e);
|
rlm@10
|
452 }
|
rlm@10
|
453 }
|
rlm@10
|
454
|
rlm@10
|
455 /**
|
rlm@10
|
456 * Sorts the items in the collection and writes it to the data output stream
|
rlm@10
|
457 *
|
rlm@10
|
458 * @param itemCollection collection of items
|
rlm@10
|
459 * @param dos a <code>DataOutputStream</code> value
|
rlm@10
|
460 * @param dotted a <code>boolean</code> value
|
rlm@10
|
461 * @throws IOException if an error occurs
|
rlm@10
|
462 */
|
rlm@10
|
463 private void writeItems(
|
rlm@10
|
464 final Collection itemCollection,
|
rlm@10
|
465 final DataOutputStream dos,
|
rlm@10
|
466 final boolean dotted) throws IOException{
|
rlm@10
|
467 int size = itemCollection.size();
|
rlm@10
|
468 Item items[] = (Item[]) itemCollection.toArray(new Item[size]);
|
rlm@10
|
469 Arrays.sort(items);
|
rlm@10
|
470 for(int i = 0; i < size; i++)
|
rlm@10
|
471 {
|
rlm@10
|
472 dos.writeUTF(items[i].name);
|
rlm@10
|
473 dos.writeInt(items[i].access);
|
rlm@10
|
474 dos.writeUTF(dotted
|
rlm@10
|
475 ? items[i].desc.replace('/', '.')
|
rlm@10
|
476 : items[i].desc);
|
rlm@10
|
477 }
|
rlm@10
|
478 }
|
rlm@10
|
479
|
rlm@10
|
480 // ------------------------------------------------------------------------
|
rlm@10
|
481 // Inner classes
|
rlm@10
|
482 // ------------------------------------------------------------------------
|
rlm@10
|
483
|
rlm@10
|
484 static class Item implements Comparable{
|
rlm@10
|
485
|
rlm@10
|
486 String name;
|
rlm@10
|
487
|
rlm@10
|
488 int access;
|
rlm@10
|
489
|
rlm@10
|
490 String desc;
|
rlm@10
|
491
|
rlm@10
|
492 Item(final String name, final int access, final String desc){
|
rlm@10
|
493 this.name = name;
|
rlm@10
|
494 this.access = access;
|
rlm@10
|
495 this.desc = desc;
|
rlm@10
|
496 }
|
rlm@10
|
497
|
rlm@10
|
498 public int compareTo(final Object o){
|
rlm@10
|
499 Item other = (Item) o;
|
rlm@10
|
500 int retVal = name.compareTo(other.name);
|
rlm@10
|
501 if(retVal == 0)
|
rlm@10
|
502 {
|
rlm@10
|
503 retVal = desc.compareTo(other.desc);
|
rlm@10
|
504 }
|
rlm@10
|
505 return retVal;
|
rlm@10
|
506 }
|
rlm@10
|
507 }
|
rlm@10
|
508 }
|