OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [tools/] [external/] [asm/] [org/] [objectweb/] [asm/] [commons/] [SerialVersionUIDAdder.java] - Blame information for rev 779

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.