Source Code Cross Referenced for Package.java in  » 6.0-JDK-Modules-com.sun.java » util » com » sun » java » util » jar » pack » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules com.sun.java » util » com.sun.java.util.jar.pack 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2001-2005 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package com.sun.java.util.jar.pack;
0027:
0028:        import java.lang.reflect.Modifier;
0029:        import java.util.*;
0030:        import java.util.zip.*;
0031:        import java.util.jar.*;
0032:        import java.io.*;
0033:        import com.sun.java.util.jar.pack.ConstantPool.*;
0034:
0035:        /**
0036:         * Define the main data structure transmitted by pack/unpack.
0037:         * @author John Rose
0038:         * @version 1.34, 05/05/07
0039:         */
0040:        class Package implements  Constants {
0041:            int verbose;
0042:            {
0043:                PropMap pmap = Utils.currentPropMap();
0044:                if (pmap != null)
0045:                    verbose = pmap.getInteger(Utils.DEBUG_VERBOSE);
0046:            }
0047:
0048:            int magic;
0049:            int package_minver;
0050:            int package_majver;
0051:
0052:            int default_modtime = NO_MODTIME;
0053:            int default_options = 0; // FO_DEFLATE_HINT
0054:
0055:            short default_class_majver = -1; // fill in later
0056:            short default_class_minver = 0; // fill in later
0057:
0058:            // These fields can be adjusted by driver properties.
0059:            short min_class_majver = JAVA_MIN_CLASS_MAJOR_VERSION;
0060:            short min_class_minver = JAVA_MIN_CLASS_MINOR_VERSION;
0061:            short max_class_majver = JAVA6_MAX_CLASS_MAJOR_VERSION;
0062:            short max_class_minver = JAVA6_MAX_CLASS_MINOR_VERSION;
0063:
0064:            short observed_max_class_majver = min_class_majver;
0065:            short observed_max_class_minver = min_class_minver;
0066:
0067:            // What constants are used in this unit?
0068:            ConstantPool.IndexGroup cp = new ConstantPool.IndexGroup();
0069:
0070:            Package() {
0071:                magic = JAVA_PACKAGE_MAGIC;
0072:                package_minver = -1; // fill in later
0073:                package_majver = 0; // fill in later
0074:            }
0075:
0076:            public void reset() {
0077:                cp = new ConstantPool.IndexGroup();
0078:                classes.clear();
0079:                files.clear();
0080:            }
0081:
0082:            int getPackageVersion() {
0083:                return (package_majver << 16) + (int) package_minver;
0084:            }
0085:
0086:            // Special empty versions of Code and InnerClasses, used for markers.
0087:            public static final Attribute.Layout attrCodeEmpty;
0088:            public static final Attribute.Layout attrInnerClassesEmpty;
0089:            public static final Attribute.Layout attrSourceFileSpecial;
0090:            public static final Map attrDefs;
0091:            static {
0092:                HashMap ad = new HashMap(2);
0093:                attrCodeEmpty = Attribute.define(ad, ATTR_CONTEXT_METHOD,
0094:                        "Code", "").layout();
0095:                attrInnerClassesEmpty = Attribute.define(ad,
0096:                        ATTR_CONTEXT_CLASS, "InnerClasses", "").layout();
0097:                attrSourceFileSpecial = Attribute.define(ad,
0098:                        ATTR_CONTEXT_CLASS, "SourceFile", "RUNH").layout();
0099:                attrDefs = Collections.unmodifiableMap(ad);
0100:            }
0101:
0102:            int getDefaultClassVersion() {
0103:                return (default_class_majver << 16)
0104:                        + (char) default_class_minver;
0105:            }
0106:
0107:            /** Return the highest version number of all classes,
0108:             *  or 0 if there are no classes.
0109:             */
0110:            int getHighestClassVersion() {
0111:                int res = 0; // initial low value
0112:                for (Iterator i = classes.iterator(); i.hasNext();) {
0113:                    Class cls = (Class) i.next();
0114:                    int ver = cls.getVersion();
0115:                    if (res < ver)
0116:                        res = ver;
0117:                }
0118:                return res;
0119:            }
0120:
0121:            /** Convenience function to choose an archive version based
0122:             *  on the class file versions observed within the archive.
0123:             */
0124:            void choosePackageVersion() {
0125:                assert (package_majver <= 0); // do not call this twice
0126:                int classver = getHighestClassVersion();
0127:                if (classver != 0
0128:                        && (classver >>> 16) < JAVA6_MAX_CLASS_MAJOR_VERSION) {
0129:                    // There are only old classfiles in this segment.
0130:                    package_majver = JAVA5_PACKAGE_MAJOR_VERSION;
0131:                    package_minver = JAVA5_PACKAGE_MINOR_VERSION;
0132:                } else {
0133:                    // Normal case.  Use the newest archive format.
0134:                    package_majver = JAVA6_PACKAGE_MAJOR_VERSION;
0135:                    package_minver = JAVA6_PACKAGE_MINOR_VERSION;
0136:                }
0137:            }
0138:
0139:            // What Java classes are in this unit?
0140:
0141:            // Fixed 6211177, converted to throw IOException
0142:            void checkVersion() throws IOException {
0143:                if (magic != JAVA_PACKAGE_MAGIC) {
0144:                    String gotMag = Integer.toHexString(magic);
0145:                    String expMag = Integer.toHexString(JAVA_PACKAGE_MAGIC);
0146:                    throw new IOException(
0147:                            "Unexpected package magic number: got " + gotMag
0148:                                    + "; expected " + expMag);
0149:                }
0150:                if ((package_majver != JAVA6_PACKAGE_MAJOR_VERSION && package_majver != JAVA5_PACKAGE_MAJOR_VERSION)
0151:                        || (package_minver != JAVA6_PACKAGE_MINOR_VERSION && package_minver != JAVA5_PACKAGE_MINOR_VERSION)) {
0152:
0153:                    String gotVer = package_majver + "." + package_minver;
0154:                    String expVer = JAVA6_PACKAGE_MAJOR_VERSION + "."
0155:                            + JAVA6_PACKAGE_MINOR_VERSION + " OR "
0156:                            + JAVA5_PACKAGE_MAJOR_VERSION + "."
0157:                            + JAVA5_PACKAGE_MINOR_VERSION;
0158:                    throw new IOException(
0159:                            "Unexpected package minor version: got " + gotVer
0160:                                    + "; expected " + expVer);
0161:                }
0162:            }
0163:
0164:            ArrayList classes = new ArrayList();
0165:
0166:            public List getClasses() {
0167:                return classes;
0168:            }
0169:
0170:            public class Class extends Attribute.Holder implements  Comparable {
0171:                public Package getPackage() {
0172:                    return Package.this ;
0173:                }
0174:
0175:                // Optional file characteristics and data source (a "class stub")
0176:                File file;
0177:
0178:                // File header
0179:                int magic;
0180:                short minver, majver;
0181:
0182:                // Local constant pool (one-way mapping of index => package cp).
0183:                Entry[] cpMap;
0184:
0185:                // Class header
0186:                //int flags;  // in Attribute.Holder.this.flags
0187:                ClassEntry this Class;
0188:                ClassEntry super Class;
0189:                ClassEntry[] interfaces;
0190:
0191:                // Class parts
0192:                ArrayList fields;
0193:                ArrayList methods;
0194:                //ArrayList attributes;  // in Attribute.Holder.this.attributes
0195:                // Note that InnerClasses may be collected at the package level.
0196:                ArrayList innerClasses;
0197:
0198:                Class(int flags, ClassEntry this Class, ClassEntry super Class,
0199:                        ClassEntry[] interfaces) {
0200:                    this .magic = JAVA_MAGIC;
0201:                    this .minver = default_class_minver;
0202:                    this .majver = default_class_majver;
0203:                    this .flags = flags;
0204:                    this .this Class = this Class;
0205:                    this .super Class = super Class;
0206:                    this .interfaces = interfaces;
0207:
0208:                    boolean added = classes.add(this );
0209:                    assert (added);
0210:                }
0211:
0212:                Class(String classFile) {
0213:                    // A blank class; must be read with a ClassReader, etc.
0214:                    initFile(newStub(classFile));
0215:                }
0216:
0217:                List getFields() {
0218:                    return fields == null ? noFields : fields;
0219:                }
0220:
0221:                List getMethods() {
0222:                    return methods == null ? noMethods : methods;
0223:                }
0224:
0225:                public String getName() {
0226:                    return this Class.stringValue();
0227:                }
0228:
0229:                int getVersion() {
0230:                    return (majver << 16) + (char) minver;
0231:                }
0232:
0233:                String getVersionString() {
0234:                    return versionStringOf(majver, minver);
0235:                }
0236:
0237:                // Note:  equals and hashCode are identity-based.
0238:                public int compareTo(Object o) {
0239:                    Class that = (Class) o;
0240:                    String n0 = this .getName();
0241:                    String n1 = that.getName();
0242:                    return n0.compareTo(n1);
0243:                }
0244:
0245:                String getObviousSourceFile() {
0246:                    return Package.getObviousSourceFile(getName());
0247:                }
0248:
0249:                private void transformSourceFile(boolean minimize) {
0250:                    // Replace "obvious" SourceFile by null.
0251:                    Attribute olda = getAttribute(attrSourceFileSpecial);
0252:                    if (olda == null)
0253:                        return; // no SourceFile attr.
0254:                    String obvious = getObviousSourceFile();
0255:                    ArrayList ref = new ArrayList(1);
0256:                    olda.visitRefs(this , VRM_PACKAGE, ref);
0257:                    Utf8Entry sfName = (Utf8Entry) ref.get(0);
0258:                    Attribute a = olda;
0259:                    if (sfName == null) {
0260:                        if (minimize) {
0261:                            // A pair of zero bytes.  Cannot use predef. layout.
0262:                            a = Attribute.find(ATTR_CONTEXT_CLASS,
0263:                                    "SourceFile", "H");
0264:                            a = a.addContent(new byte[2]);
0265:                        } else {
0266:                            // Expand null attribute to the obvious string.
0267:                            byte[] bytes = new byte[2];
0268:                            sfName = getRefString(obvious);
0269:                            Object f = null;
0270:                            f = Fixups.add(f, bytes, 0, Fixups.U2_FORMAT,
0271:                                    sfName);
0272:                            a = attrSourceFileSpecial.addContent(bytes, f);
0273:                        }
0274:                    } else if (obvious.equals(sfName.stringValue())) {
0275:                        if (minimize) {
0276:                            // Replace by an all-zero attribute.
0277:                            a = attrSourceFileSpecial.addContent(new byte[2]);
0278:                        } else {
0279:                            assert (false);
0280:                        }
0281:                    }
0282:                    if (a != olda) {
0283:                        if (verbose > 2)
0284:                            Utils.log.fine("recoding obvious SourceFile="
0285:                                    + obvious);
0286:                        List newAttrs = new ArrayList(getAttributes());
0287:                        int where = newAttrs.indexOf(olda);
0288:                        newAttrs.set(where, a);
0289:                        setAttributes(newAttrs);
0290:                    }
0291:                }
0292:
0293:                void minimizeSourceFile() {
0294:                    transformSourceFile(true);
0295:                }
0296:
0297:                void expandSourceFile() {
0298:                    transformSourceFile(false);
0299:                }
0300:
0301:                protected Entry[] getCPMap() {
0302:                    return cpMap;
0303:                }
0304:
0305:                protected void setCPMap(Entry[] cpMap) {
0306:                    this .cpMap = cpMap;
0307:                }
0308:
0309:                boolean hasInnerClasses() {
0310:                    return innerClasses != null;
0311:                }
0312:
0313:                List getInnerClasses() {
0314:                    return innerClasses;
0315:                }
0316:
0317:                public void setInnerClasses(Collection ics) {
0318:                    innerClasses = (ics == null) ? null : new ArrayList(ics);
0319:                    // Edit the attribute list, if necessary.
0320:                    Attribute a = getAttribute(attrInnerClassesEmpty);
0321:                    if (innerClasses != null && a == null)
0322:                        addAttribute(attrInnerClassesEmpty.canonicalInstance());
0323:                    else if (innerClasses == null && a != null)
0324:                        removeAttribute(a);
0325:                }
0326:
0327:                /** Given a global map of ICs (keyed by thisClass),
0328:                 *  compute the subset of its Map.values which are
0329:                 *  required to be present in the local InnerClasses
0330:                 *  attribute.  Perform this calculation without
0331:                 *  reference to any actual InnerClasses attribute.
0332:                 *  <p>
0333:                 *  The order of the resulting list is consistent
0334:                 *  with that of Package.this.allInnerClasses.
0335:                 */
0336:                public List computeGloballyImpliedICs() {
0337:                    HashSet cpRefs = new HashSet();
0338:                    { // This block temporarily displaces this.innerClasses.
0339:                        ArrayList innerClassesSaved = innerClasses;
0340:                        innerClasses = null; // ignore for the moment
0341:                        visitRefs(VRM_CLASSIC, cpRefs);
0342:                        innerClasses = innerClassesSaved;
0343:                    }
0344:                    ConstantPool.completeReferencesIn(cpRefs, true);
0345:
0346:                    HashSet icRefs = new HashSet();
0347:                    for (Iterator i = cpRefs.iterator(); i.hasNext();) {
0348:                        Entry e = (Entry) i.next();
0349:                        // Restrict cpRefs to InnerClasses entries only.
0350:                        if (!(e instanceof  ClassEntry))
0351:                            continue;
0352:                        // For every IC reference, add its outers also.
0353:                        while (e != null) {
0354:                            InnerClass ic = getGlobalInnerClass(e);
0355:                            if (ic == null)
0356:                                break;
0357:                            if (!icRefs.add(e))
0358:                                break;
0359:                            e = ic.outerClass;
0360:                            // If we add A$B$C to the mix, we must also add A$B.
0361:                        }
0362:                    }
0363:                    // This loop is structured this way so as to accumulate
0364:                    // entries into impliedICs in an order which reflects
0365:                    // the order of allInnerClasses.
0366:                    ArrayList impliedICs = new ArrayList();
0367:                    for (Iterator i = allInnerClasses.iterator(); i.hasNext();) {
0368:                        InnerClass ic = (InnerClass) i.next();
0369:                        // This one is locally relevant if it describes
0370:                        // a member of the current class, or if the current
0371:                        // class uses it somehow.  In the particular case
0372:                        // where thisClass is an inner class, it will already
0373:                        // be a member of icRefs.
0374:                        if (icRefs.contains(ic.this Class)
0375:                                || ic.outerClass == this .this Class) {
0376:                            // Add every relevant class to the IC attribute:
0377:                            if (verbose > 1)
0378:                                Utils.log.fine("Relevant IC: " + ic);
0379:                            impliedICs.add(ic);
0380:                        }
0381:                    }
0382:                    return impliedICs;
0383:                }
0384:
0385:                // Helper for both minimizing and expanding.
0386:                // Computes a symmetric difference.
0387:                private List computeICdiff() {
0388:                    List impliedICs = computeGloballyImpliedICs();
0389:                    List actualICs = getInnerClasses();
0390:                    if (actualICs == null)
0391:                        actualICs = Collections.EMPTY_LIST;
0392:
0393:                    // Symmetric difference is calculated from I, A like this:
0394:                    //  diff = (I+A) - (I*A)
0395:                    // Note that the center C is unordered, but the result
0396:                    // preserves the original ordering of I and A.
0397:                    //
0398:                    // Class file rules require that outers precede inners.
0399:                    // So, add I before A, in case A$B$Z is local, but A$B
0400:                    // is implicit.  The reverse is never the case.
0401:                    if (actualICs.isEmpty()) {
0402:                        return impliedICs;
0403:                        // Diff is I since A is empty.
0404:                    }
0405:                    if (impliedICs.isEmpty()) {
0406:                        return actualICs;
0407:                        // Diff is A since I is empty.
0408:                    }
0409:                    // (I*A) is non-trivial
0410:                    HashSet center = new HashSet(actualICs);
0411:                    center.retainAll(new HashSet(impliedICs));
0412:                    impliedICs.addAll(actualICs);
0413:                    impliedICs.removeAll(center);
0414:                    // Diff is now I^A = (I+A)-(I*A).
0415:                    return impliedICs;
0416:                }
0417:
0418:                /** When packing, anticipate the effect of expandLocalICs.
0419:                 *  Replace the local ICs by their symmetric difference
0420:                 *  with the globally implied ICs for this class; if this
0421:                 *  difference is empty, remove the local ICs altogether.
0422:                 *  <p>
0423:                 *  An empty local IC attribute is reserved to signal
0424:                 *  the unpacker to delete the attribute altogether,
0425:                 *  so a missing local IC attribute signals the unpacker
0426:                 *  to use the globally implied ICs changed.
0427:                 */
0428:                void minimizeLocalICs() {
0429:                    List diff = computeICdiff();
0430:                    List actualICs = innerClasses;
0431:                    List localICs; // will be the diff, modulo edge cases
0432:                    if (diff.isEmpty()) {
0433:                        // No diff, so transmit no attribute.
0434:                        localICs = null;
0435:                        if (actualICs != null && actualICs.isEmpty()) {
0436:                            // Odd case:  No implied ICs, and a zero length attr.
0437:                            // Do not support it directly.
0438:                            if (verbose > 0)
0439:                                Utils.log
0440:                                        .info("Warning: Dropping empty InnerClasses attribute from "
0441:                                                + this );
0442:                        }
0443:                    } else if (actualICs == null) {
0444:                        // No local IC attribute, even though some are implied.
0445:                        // Signal with trivial attribute.
0446:                        localICs = Collections.EMPTY_LIST;
0447:                    } else {
0448:                        // Transmit a non-empty diff, which will create
0449:                        // a local ICs attribute.
0450:                        localICs = diff;
0451:                    }
0452:                    // Reduce the set to the symmetric difference.
0453:                    setInnerClasses(localICs);
0454:                    if (verbose > 1 && localICs != null)
0455:                        Utils.log.fine("keeping local ICs in " + this  + ": "
0456:                                + localICs);
0457:                }
0458:
0459:                /** When unpacking, undo the effect of minimizeLocalICs.
0460:                 *  Must return negative if any IC tuples may have been deleted.
0461:                 *  Otherwise, return positive if any IC tuples were added.
0462:                 */
0463:                int expandLocalICs() {
0464:                    List localICs = innerClasses;
0465:                    List actualICs;
0466:                    int changed;
0467:                    if (localICs == null) {
0468:                        // Diff was empty.  (Common case.)
0469:                        List impliedICs = computeGloballyImpliedICs();
0470:                        if (impliedICs.isEmpty()) {
0471:                            actualICs = null;
0472:                            changed = 0;
0473:                        } else {
0474:                            actualICs = impliedICs;
0475:                            changed = 1; // added more tuples
0476:                        }
0477:                    } else if (localICs.isEmpty()) {
0478:                        // It was a non-empty diff, but the local ICs were absent.
0479:                        actualICs = null;
0480:                        changed = 0; // [] => null, no tuple change
0481:                    } else {
0482:                        // Non-trivial diff was transmitted.
0483:                        actualICs = computeICdiff();
0484:                        // If we only added more ICs, return +1.
0485:                        changed = actualICs.containsAll(localICs) ? +1 : -1;
0486:                    }
0487:                    setInnerClasses(actualICs);
0488:                    return changed;
0489:                }
0490:
0491:                public abstract class Member extends Attribute.Holder implements 
0492:                        Comparable {
0493:                    DescriptorEntry descriptor;
0494:
0495:                    protected Member(int flags, DescriptorEntry descriptor) {
0496:                        this .flags = flags;
0497:                        this .descriptor = descriptor;
0498:                    }
0499:
0500:                    public Class this Class() {
0501:                        return Class.this ;
0502:                    }
0503:
0504:                    public DescriptorEntry getDescriptor() {
0505:                        return descriptor;
0506:                    }
0507:
0508:                    public String getName() {
0509:                        return descriptor.nameRef.stringValue();
0510:                    }
0511:
0512:                    public String getType() {
0513:                        return descriptor.typeRef.stringValue();
0514:                    }
0515:
0516:                    protected Entry[] getCPMap() {
0517:                        return cpMap;
0518:                    }
0519:
0520:                    protected void visitRefs(int mode, Collection refs) {
0521:                        if (verbose > 2)
0522:                            Utils.log.fine("visitRefs " + this );
0523:                        // Careful:  The descriptor is used by the package,
0524:                        // but the classfile breaks it into component refs.
0525:                        if (mode == VRM_CLASSIC) {
0526:                            refs.add(descriptor.nameRef);
0527:                            refs.add(descriptor.typeRef);
0528:                        } else {
0529:                            refs.add(descriptor);
0530:                        }
0531:                        // Handle attribute list:
0532:                        super .visitRefs(mode, refs);
0533:                    }
0534:
0535:                    public String toString() {
0536:                        return Class.this  + "." + descriptor.prettyString();
0537:                    }
0538:                }
0539:
0540:                public class Field extends Member {
0541:                    // Order is significant for fields:  It is visible to reflection.
0542:                    int order;
0543:
0544:                    public Field(int flags, DescriptorEntry descriptor) {
0545:                        super (flags, descriptor);
0546:                        assert (!descriptor.isMethod());
0547:                        if (fields == null)
0548:                            fields = new ArrayList();
0549:                        boolean added = fields.add(this );
0550:                        assert (added);
0551:                        order = fields.size();
0552:                    }
0553:
0554:                    public byte getLiteralTag() {
0555:                        return descriptor.getLiteralTag();
0556:                    }
0557:
0558:                    public int compareTo(Object o) {
0559:                        Field that = (Field) o;
0560:                        return this .order - that.order;
0561:                    }
0562:                }
0563:
0564:                public class Method extends Member {
0565:                    // Code attribute is specially hardwired.
0566:                    Code code;
0567:
0568:                    public Method(int flags, DescriptorEntry descriptor) {
0569:                        super (flags, descriptor);
0570:                        assert (descriptor.isMethod());
0571:                        if (methods == null)
0572:                            methods = new ArrayList();
0573:                        boolean added = methods.add(this );
0574:                        assert (added);
0575:                    }
0576:
0577:                    public void trimToSize() {
0578:                        super .trimToSize();
0579:                        if (code != null)
0580:                            code.trimToSize();
0581:                    }
0582:
0583:                    public int getArgumentSize() {
0584:                        int argSize = descriptor.typeRef.computeSize(true);
0585:                        int this Size = Modifier.isStatic(flags) ? 0 : 1;
0586:                        return this Size + argSize;
0587:                    }
0588:
0589:                    // Sort methods in a canonical order (by type, then by name).
0590:                    public int compareTo(Object o) {
0591:                        Method that = (Method) o;
0592:                        return this .getDescriptor().compareTo(
0593:                                that.getDescriptor());
0594:                    }
0595:
0596:                    public void strip(String attrName) {
0597:                        if (attrName == "Code")
0598:                            code = null;
0599:                        if (code != null)
0600:                            code.strip(attrName);
0601:                        super .strip(attrName);
0602:                    }
0603:
0604:                    protected void visitRefs(int mode, Collection refs) {
0605:                        super .visitRefs(mode, refs);
0606:                        if (code != null) {
0607:                            if (mode == VRM_CLASSIC) {
0608:                                refs.add(getRefString("Code"));
0609:                            }
0610:                            code.visitRefs(mode, refs);
0611:                        }
0612:                    }
0613:                }
0614:
0615:                public void trimToSize() {
0616:                    super .trimToSize();
0617:                    for (int isM = 0; isM <= 1; isM++) {
0618:                        ArrayList members = (isM == 0) ? fields : methods;
0619:                        if (members == null)
0620:                            continue;
0621:                        members.trimToSize();
0622:                        for (Iterator i = members.iterator(); i.hasNext();) {
0623:                            Member m = (Member) i.next();
0624:                            m.trimToSize();
0625:                        }
0626:                    }
0627:                    if (innerClasses != null) {
0628:                        innerClasses.trimToSize();
0629:                    }
0630:                }
0631:
0632:                public void strip(String attrName) {
0633:                    if (attrName == "InnerClass")
0634:                        innerClasses = null;
0635:                    for (int isM = 0; isM <= 1; isM++) {
0636:                        ArrayList members = (isM == 0) ? fields : methods;
0637:                        if (members == null)
0638:                            continue;
0639:                        for (Iterator i = members.iterator(); i.hasNext();) {
0640:                            Member m = (Member) i.next();
0641:                            m.strip(attrName);
0642:                        }
0643:                    }
0644:                    super .strip(attrName);
0645:                }
0646:
0647:                protected void visitRefs(int mode, Collection refs) {
0648:                    if (verbose > 2)
0649:                        Utils.log.fine("visitRefs " + this );
0650:                    refs.add(this Class);
0651:                    refs.add(super Class);
0652:                    for (int i = 0; i < interfaces.length; i++) {
0653:                        refs.add(interfaces[i]);
0654:                    }
0655:                    for (int isM = 0; isM <= 1; isM++) {
0656:                        ArrayList members = (isM == 0) ? fields : methods;
0657:                        if (members == null)
0658:                            continue;
0659:                        for (Iterator i = members.iterator(); i.hasNext();) {
0660:                            Member m = (Member) i.next();
0661:                            boolean ok = false;
0662:                            try {
0663:                                m.visitRefs(mode, refs);
0664:                                ok = true;
0665:                            } finally {
0666:                                if (!ok)
0667:                                    Utils.log.warning("Error scanning " + m);
0668:                            }
0669:                        }
0670:                    }
0671:                    visitInnerClassRefs(mode, refs);
0672:                    // Handle attribute list:
0673:                    super .visitRefs(mode, refs);
0674:                }
0675:
0676:                protected void visitInnerClassRefs(int mode, Collection refs) {
0677:                    Package.visitInnerClassRefs(innerClasses, mode, refs);
0678:                }
0679:
0680:                // Hook called by ClassReader when it's done.
0681:                void finishReading() {
0682:                    trimToSize();
0683:                    maybeChooseFileName();
0684:                }
0685:
0686:                public void initFile(File file) {
0687:                    assert (this .file == null); // set-once
0688:                    if (file == null) {
0689:                        // Build a trivial stub.
0690:                        file = newStub(canonicalFileName());
0691:                    }
0692:                    this .file = file;
0693:                    assert (file.isClassStub());
0694:                    file.stubClass = this ;
0695:                    maybeChooseFileName();
0696:                }
0697:
0698:                public void maybeChooseFileName() {
0699:                    if (this Class == null) {
0700:                        return; // do not choose yet
0701:                    }
0702:                    String canonName = canonicalFileName();
0703:                    if (file.nameString.equals("")) {
0704:                        file.nameString = canonName;
0705:                    }
0706:                    if (file.nameString.equals(canonName)) {
0707:                        // The file name is predictable.  Transmit "".
0708:                        file.name = getRefString("");
0709:                        return;
0710:                    }
0711:                    // If name has not yet been looked up, find it now.
0712:                    if (file.name == null) {
0713:                        file.name = getRefString(file.nameString);
0714:                    }
0715:                }
0716:
0717:                public String canonicalFileName() {
0718:                    if (this Class == null)
0719:                        return null;
0720:                    return this Class.stringValue() + ".class";
0721:                }
0722:
0723:                public java.io.File getFileName(java.io.File parent) {
0724:                    String name = file.name.stringValue();
0725:                    if (name.equals(""))
0726:                        name = canonicalFileName();
0727:                    String fname = name
0728:                            .replace('/', java.io.File.separatorChar);
0729:                    return new java.io.File(parent, fname);
0730:                }
0731:
0732:                public java.io.File getFileName() {
0733:                    return getFileName(null);
0734:                }
0735:
0736:                public String toString() {
0737:                    return this Class.stringValue();
0738:                }
0739:            }
0740:
0741:            void addClass(Class c) {
0742:                assert (c.getPackage() == this );
0743:                boolean added = classes.add(c);
0744:                assert (added);
0745:                // Make sure the class is represented in the total file order:
0746:                if (c.file == null)
0747:                    c.initFile(null);
0748:                addFile(c.file);
0749:            }
0750:
0751:            // What non-class files are in this unit?
0752:            ArrayList files = new ArrayList();
0753:
0754:            public List getFiles() {
0755:                return files;
0756:            }
0757:
0758:            public List getClassStubs() {
0759:                ArrayList classStubs = new ArrayList(classes.size());
0760:                for (Iterator i = classes.iterator(); i.hasNext();) {
0761:                    Class cls = (Class) i.next();
0762:                    assert (cls.file.isClassStub());
0763:                    classStubs.add(cls.file);
0764:                }
0765:                return classStubs;
0766:            }
0767:
0768:            public class File implements  Comparable {
0769:                String nameString; // true name of this file
0770:                Utf8Entry name;
0771:                int modtime = NO_MODTIME;
0772:                int options = 0; // random flag bits, such as deflate_hint
0773:                Class stubClass; // if this is a stub, here's the class
0774:                ArrayList prepend = new ArrayList(); // list of byte[]
0775:                java.io.ByteArrayOutputStream append = new ByteArrayOutputStream();
0776:
0777:                File(Utf8Entry name) {
0778:                    this .name = name;
0779:                    this .nameString = name.stringValue();
0780:                    // caller must fill in contents
0781:                }
0782:
0783:                File(String nameString) {
0784:                    nameString = fixupFileName(nameString);
0785:                    this .name = getRefString(nameString);
0786:                    this .nameString = name.stringValue();
0787:                }
0788:
0789:                public boolean isDirectory() {
0790:                    // JAR directory.  Useless.
0791:                    return nameString.endsWith("/");
0792:                }
0793:
0794:                public boolean isClassStub() {
0795:                    return (options & FO_IS_CLASS_STUB) != 0;
0796:                }
0797:
0798:                public Class getStubClass() {
0799:                    assert (isClassStub());
0800:                    assert (stubClass != null);
0801:                    return stubClass;
0802:                }
0803:
0804:                public boolean isTrivialClassStub() {
0805:                    return isClassStub()
0806:                            && name.stringValue().equals("")
0807:                            && (modtime == NO_MODTIME || modtime == default_modtime)
0808:                            && (options & ~FO_IS_CLASS_STUB) == 0;
0809:                }
0810:
0811:                // The nameString is the key.  Ignore other things.
0812:                // (Note:  The name might be "", in the case of a trivial class stub.)
0813:                public boolean equals(Object o) {
0814:                    File that = (File) o;
0815:                    return that.nameString == this .nameString;
0816:                }
0817:
0818:                public int hashCode() {
0819:                    return nameString.hashCode();
0820:                }
0821:
0822:                // Simple alphabetic sort.  PackageWriter uses a better comparator.
0823:                public int compareTo(Object o) {
0824:                    File that = (File) o;
0825:                    return this .nameString.compareTo(that.nameString);
0826:                }
0827:
0828:                public String toString() {
0829:                    return nameString
0830:                            + "{"
0831:                            + (isClassStub() ? "*" : "")
0832:                            + (BandStructure.testBit(options, FO_DEFLATE_HINT) ? "@"
0833:                                    : "")
0834:                            + (modtime == NO_MODTIME ? "" : "M" + modtime)
0835:                            + (getFileLength() == 0 ? "" : "["
0836:                                    + getFileLength() + "]") + "}";
0837:                }
0838:
0839:                public java.io.File getFileName() {
0840:                    return getFileName(null);
0841:                }
0842:
0843:                public java.io.File getFileName(java.io.File parent) {
0844:                    String name = this .nameString;
0845:                    //if (name.startsWith("./"))  name = name.substring(2);
0846:                    String fname = name
0847:                            .replace('/', java.io.File.separatorChar);
0848:                    return new java.io.File(parent, fname);
0849:                }
0850:
0851:                public void addBytes(byte[] bytes) {
0852:                    addBytes(bytes, 0, bytes.length);
0853:                }
0854:
0855:                public void addBytes(byte[] bytes, int off, int len) {
0856:                    if (((append.size() | len) << 2) < 0) {
0857:                        prepend.add(append.toByteArray());
0858:                        append.reset();
0859:                    }
0860:                    append.write(bytes, off, len);
0861:                }
0862:
0863:                public long getFileLength() {
0864:                    long len = 0;
0865:                    if (prepend == null && append == null)
0866:                        return 0;
0867:                    for (Iterator i = prepend.iterator(); i.hasNext();) {
0868:                        byte[] block = (byte[]) i.next();
0869:                        len += block.length;
0870:                    }
0871:                    len += append.size();
0872:                    return len;
0873:                }
0874:
0875:                public void writeTo(OutputStream out) throws IOException {
0876:                    if (prepend == null && append == null)
0877:                        return;
0878:                    for (Iterator i = prepend.iterator(); i.hasNext();) {
0879:                        byte[] block = (byte[]) i.next();
0880:                        out.write(block);
0881:                    }
0882:                    append.writeTo(out);
0883:                }
0884:
0885:                public void readFrom(InputStream in) throws IOException {
0886:                    byte[] buf = new byte[1 << 16];
0887:                    int nr;
0888:                    while ((nr = in.read(buf)) > 0) {
0889:                        addBytes(buf, 0, nr);
0890:                    }
0891:                }
0892:
0893:                public InputStream getInputStream() {
0894:                    InputStream in = new ByteArrayInputStream(append
0895:                            .toByteArray());
0896:                    if (prepend.size() == 0)
0897:                        return in;
0898:                    ArrayList isa = new ArrayList(prepend.size() + 1);
0899:                    for (Iterator i = prepend.iterator(); i.hasNext();) {
0900:                        byte[] bytes = (byte[]) i.next();
0901:                        isa.add(new ByteArrayInputStream(bytes));
0902:                    }
0903:                    isa.add(in);
0904:                    return new SequenceInputStream(Collections.enumeration(isa));
0905:                }
0906:
0907:                protected void visitRefs(int mode, Collection refs) {
0908:                    assert (name != null);
0909:                    refs.add(name);
0910:                }
0911:            }
0912:
0913:            File newStub(String classFileNameString) {
0914:                File stub = new File(classFileNameString);
0915:                stub.options |= FO_IS_CLASS_STUB;
0916:                stub.prepend = null;
0917:                stub.append = null; // do not collect data
0918:                return stub;
0919:            }
0920:
0921:            private static String fixupFileName(String name) {
0922:                String fname = name.replace(java.io.File.separatorChar, '/');
0923:                if (fname.startsWith("/")) {
0924:                    throw new IllegalArgumentException("absolute file name "
0925:                            + fname);
0926:                }
0927:                return fname;
0928:            }
0929:
0930:            void addFile(File file) {
0931:                boolean added = files.add(file);
0932:                assert (added);
0933:            }
0934:
0935:            // Is there a globally declared table of inner classes?
0936:            ArrayList allInnerClasses = new ArrayList();
0937:            HashMap allInnerClassesByThis;
0938:
0939:            public List getAllInnerClasses() {
0940:                return allInnerClasses;
0941:            }
0942:
0943:            public void setAllInnerClasses(Collection ics) {
0944:                assert (ics != allInnerClasses);
0945:                allInnerClasses.clear();
0946:                allInnerClasses.addAll(ics);
0947:
0948:                // Make an index:
0949:                allInnerClassesByThis = new HashMap(allInnerClasses.size());
0950:                for (Iterator i = allInnerClasses.iterator(); i.hasNext();) {
0951:                    InnerClass ic = (InnerClass) i.next();
0952:                    Object pic = allInnerClassesByThis.put(ic.this Class, ic);
0953:                    assert (pic == null); // caller must ensure key uniqueness!
0954:                }
0955:            }
0956:
0957:            /** Return a global inner class record for the given thisClass. */
0958:            public InnerClass getGlobalInnerClass(Entry this Class) {
0959:                assert (this Class instanceof  ClassEntry);
0960:                return (InnerClass) allInnerClassesByThis.get(this Class);
0961:            }
0962:
0963:            static class InnerClass implements  Comparable {
0964:                final ClassEntry this Class;
0965:                final ClassEntry outerClass;
0966:                final Utf8Entry name;
0967:                final int flags;
0968:
0969:                // Can name and outerClass be derived from thisClass?
0970:                final boolean predictable;
0971:
0972:                // About 30% of inner classes are anonymous (in rt.jar).
0973:                // About 60% are class members; the rest are named locals.
0974:                // Nearly all have predictable outers and names.
0975:
0976:                InnerClass(ClassEntry this Class, ClassEntry outerClass,
0977:                        Utf8Entry name, int flags) {
0978:                    this .this Class = this Class;
0979:                    this .outerClass = outerClass;
0980:                    this .name = name;
0981:                    this .flags = flags;
0982:                    this .predictable = computePredictable();
0983:                }
0984:
0985:                private boolean computePredictable() {
0986:                    //System.out.println("computePredictable "+outerClass+" "+this.name);
0987:                    String[] parse = parseInnerClassName(this Class
0988:                            .stringValue());
0989:                    if (parse == null)
0990:                        return false;
0991:                    String pkgOuter = parse[0];
0992:                    //String number = parse[1];
0993:                    String name = parse[2];
0994:                    String haveName = (this .name == null) ? null : this .name
0995:                            .stringValue();
0996:                    String haveOuter = (outerClass == null) ? null : outerClass
0997:                            .stringValue();
0998:                    boolean predictable = (name == haveName && pkgOuter == haveOuter);
0999:                    //System.out.println("computePredictable => "+predictable);
1000:                    return predictable;
1001:                }
1002:
1003:                public boolean equals(Object o) {
1004:                    if (o == null)
1005:                        return false;
1006:                    InnerClass that = (InnerClass) o;
1007:                    return eq(this .this Class, that.this Class)
1008:                            && eq(this .outerClass, that.outerClass)
1009:                            && eq(this .name, that.name)
1010:                            && this .flags == that.flags;
1011:                }
1012:
1013:                private static boolean eq(Object x, Object y) {
1014:                    return (x == null) ? y == null : x.equals(y);
1015:                }
1016:
1017:                public int hashCode() {
1018:                    return this Class.hashCode();
1019:                }
1020:
1021:                public int compareTo(Object o) {
1022:                    InnerClass that = (InnerClass) o;
1023:                    return this .this Class.compareTo(that.this Class);
1024:                }
1025:
1026:                protected void visitRefs(int mode, Collection refs) {
1027:                    refs.add(this Class);
1028:                    if (mode == VRM_CLASSIC || !predictable) {
1029:                        // If the name can be demangled, the package omits
1030:                        // the products of demangling.  Otherwise, include them.
1031:                        refs.add(outerClass);
1032:                        refs.add(name);
1033:                    }
1034:                }
1035:
1036:                public String toString() {
1037:                    return this Class.stringValue();
1038:                }
1039:            }
1040:
1041:            // Helper for building InnerClasses attributes.
1042:            static private void visitInnerClassRefs(Collection innerClasses,
1043:                    int mode, Collection refs) {
1044:                if (innerClasses == null) {
1045:                    return; // no attribute; nothing to do
1046:                }
1047:                if (mode == VRM_CLASSIC) {
1048:                    refs.add(getRefString("InnerClasses"));
1049:                }
1050:                if (innerClasses.size() > 0) {
1051:                    // Count the entries themselves:
1052:                    for (Iterator i = innerClasses.iterator(); i.hasNext();) {
1053:                        InnerClass c = (InnerClass) i.next();
1054:                        c.visitRefs(mode, refs);
1055:                    }
1056:                }
1057:            }
1058:
1059:            static String[] parseInnerClassName(String n) {
1060:                //System.out.println("parseInnerClassName "+n);
1061:                String pkgOuter, number, name;
1062:                int dollar1, dollar2; // pointers to $ in the pattern
1063:                // parse n = (<pkg>/)*<outer>($<number>)?($<name>)?
1064:                int nlen = n.length();
1065:                int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, n.length()) + 1;
1066:                dollar2 = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n, n.length());
1067:                if (dollar2 < pkglen)
1068:                    return null;
1069:                if (isDigitString(n, dollar2 + 1, nlen)) {
1070:                    // n = (<pkg>/)*<outer>$<number>
1071:                    number = n.substring(dollar2 + 1, nlen);
1072:                    name = null;
1073:                    dollar1 = dollar2;
1074:                } else if ((dollar1 = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n,
1075:                        dollar2 - 1)) > pkglen
1076:                        && isDigitString(n, dollar1 + 1, dollar2)) {
1077:                    // n = (<pkg>/)*<outer>$<number>$<name>
1078:                    number = n.substring(dollar1 + 1, dollar2);
1079:                    name = n.substring(dollar2 + 1, nlen).intern();
1080:                } else {
1081:                    // n = (<pkg>/)*<outer>$<name>
1082:                    dollar1 = dollar2;
1083:                    number = null;
1084:                    name = n.substring(dollar2 + 1, nlen).intern();
1085:                }
1086:                if (number == null)
1087:                    pkgOuter = n.substring(0, dollar1).intern();
1088:                else
1089:                    pkgOuter = null;
1090:                //System.out.println("parseInnerClassName parses "+pkgOuter+" "+number+" "+name);
1091:                return new String[] { pkgOuter, number, name };
1092:            }
1093:
1094:            private static final int SLASH_MIN = '.';
1095:            private static final int SLASH_MAX = '/';
1096:            private static final int DOLLAR_MIN = 0;
1097:            private static final int DOLLAR_MAX = '-';
1098:            static {
1099:                assert (lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, "x$$y$", 4) == 2);
1100:                assert (lastIndexOf(SLASH_MIN, SLASH_MAX, "x//y/", 4) == 2);
1101:            }
1102:
1103:            private static int lastIndexOf(int chMin, int chMax, String str,
1104:                    int pos) {
1105:                for (int i = pos; --i >= 0;) {
1106:                    int ch = str.charAt(i);
1107:                    if (ch >= chMin && ch <= chMax) {
1108:                        return i;
1109:                    }
1110:                }
1111:                return -1;
1112:            }
1113:
1114:            private static boolean isDigitString(String x, int beg, int end) {
1115:                if (beg == end)
1116:                    return false; // null string
1117:                for (int i = beg; i < end; i++) {
1118:                    char ch = x.charAt(i);
1119:                    if (!(ch >= '0' && ch <= '9'))
1120:                        return false;
1121:                }
1122:                return true;
1123:            }
1124:
1125:            static String getObviousSourceFile(String className) {
1126:                String n = className;
1127:                int pkglen = lastIndexOf(SLASH_MIN, SLASH_MAX, n, n.length()) + 1;
1128:                n = n.substring(pkglen);
1129:                int cutoff = n.length();
1130:                for (;;) {
1131:                    // Work backwards, finding all '$', '#', etc.
1132:                    int dollar2 = lastIndexOf(DOLLAR_MIN, DOLLAR_MAX, n,
1133:                            cutoff - 1);
1134:                    if (dollar2 < 0)
1135:                        break;
1136:                    cutoff = dollar2;
1137:                    if (cutoff == 0)
1138:                        break;
1139:                }
1140:                String obvious = n.substring(0, cutoff) + ".java";
1141:                return obvious;
1142:            }
1143:
1144:            /*
1145:             static {
1146:             assert(getObviousSourceFile("foo").equals("foo.java"));
1147:             assert(getObviousSourceFile("foo/bar").equals("bar.java"));
1148:             assert(getObviousSourceFile("foo/bar$baz").equals("bar.java"));
1149:             assert(getObviousSourceFile("foo/bar#baz#1").equals("bar.java"));
1150:             assert(getObviousSourceFile("foo.bar.baz#1").equals("baz.java"));
1151:             }
1152:             */
1153:
1154:            static Utf8Entry getRefString(String s) {
1155:                return ConstantPool.getUtf8Entry(s);
1156:            }
1157:
1158:            static LiteralEntry getRefLiteral(Comparable s) {
1159:                return ConstantPool.getLiteralEntry(s);
1160:            }
1161:
1162:            void stripAttributeKind(String what) {
1163:                // what is one of { Debug, Compile, Constant, Exceptions, InnerClasses }
1164:                if (verbose > 0)
1165:                    Utils.log.info("Stripping " + what.toLowerCase()
1166:                            + " data and attributes...");
1167:                if (what == "Debug") {
1168:                    strip("SourceFile");
1169:                    strip("LineNumberTable");
1170:                    strip("LocalVariableTable");
1171:                    strip("LocalVariableTypeTable");
1172:                }
1173:                if (what == "Compile") {
1174:                    // Keep the inner classes normally.
1175:                    // Although they have no effect on execution,
1176:                    // the Reflection API exposes them, and JCK checks them.
1177:                    // NO: // strip("InnerClasses");
1178:                    strip("Deprecated");
1179:                    strip("Synthetic");
1180:                }
1181:                if (what == "Exceptions") {
1182:                    // Keep the exceptions normally.
1183:                    // Although they have no effect on execution,
1184:                    // the Reflection API exposes them, and JCK checks them.
1185:                    strip("Exceptions");
1186:                }
1187:                if (what == "Constant") {
1188:                    stripConstantFields();
1189:                }
1190:            }
1191:
1192:            public void trimToSize() {
1193:                classes.trimToSize();
1194:                for (Iterator i = classes.iterator(); i.hasNext();) {
1195:                    Class c = (Class) i.next();
1196:                    c.trimToSize();
1197:                }
1198:                files.trimToSize();
1199:            }
1200:
1201:            public void strip(String attrName) {
1202:                for (Iterator i = classes.iterator(); i.hasNext();) {
1203:                    Class c = (Class) i.next();
1204:                    c.strip(attrName);
1205:                }
1206:            }
1207:
1208:            public static String versionStringOf(int majver, int minver) {
1209:                return majver + "." + minver;
1210:            }
1211:
1212:            public static String versionStringOf(int version) {
1213:                return versionStringOf(version >>> 16, (char) version);
1214:            }
1215:
1216:            public void stripConstantFields() {
1217:                for (Iterator i = classes.iterator(); i.hasNext();) {
1218:                    Class c = (Class) i.next();
1219:                    for (Iterator j = c.fields.iterator(); j.hasNext();) {
1220:                        Class.Field f = (Class.Field) j.next();
1221:                        if (Modifier.isFinal(f.flags)
1222:                                // do not strip non-static finals:
1223:                                && Modifier.isStatic(f.flags)
1224:                                && f.getAttribute("ConstantValue") != null
1225:                                && !f.getName().startsWith("serial")) {
1226:                            if (verbose > 2) {
1227:                                Utils.log.fine(">> Strip " + this 
1228:                                        + " ConstantValue");
1229:                                j.remove();
1230:                            }
1231:                        }
1232:                    }
1233:                }
1234:            }
1235:
1236:            protected void visitRefs(int mode, Collection refs) {
1237:                for (Iterator i = classes.iterator(); i.hasNext();) {
1238:                    Class c = (Class) i.next();
1239:                    c.visitRefs(mode, refs);
1240:                }
1241:                if (mode != VRM_CLASSIC) {
1242:                    for (Iterator i = files.iterator(); i.hasNext();) {
1243:                        File f = (File) i.next();
1244:                        f.visitRefs(mode, refs);
1245:                    }
1246:                    visitInnerClassRefs(allInnerClasses, mode, refs);
1247:                }
1248:            }
1249:
1250:            // Use this before writing the package file.
1251:            // It sorts files into a new order which seems likely to
1252:            // compress better.  It also moves classes to the end of the
1253:            // file order.  It also removes JAR directory entries, which
1254:            // are useless.
1255:            void reorderFiles(boolean keepClassOrder, boolean stripDirectories) {
1256:                // First reorder the classes, if that is allowed.
1257:                if (!keepClassOrder) {
1258:                    // In one test with rt.jar, this trick gained 0.7%
1259:                    Collections.sort(classes);
1260:                }
1261:
1262:                // Remove stubs from resources; maybe we'll add them on at the end,
1263:                // if there are some non-trivial ones.  The best case is that
1264:                // modtimes and options are not transmitted, and the stub files
1265:                // for class files do not need to be transmitted at all.
1266:                // Also 
1267:                List stubs = getClassStubs();
1268:                for (Iterator i = files.iterator(); i.hasNext();) {
1269:                    File file = (File) i.next();
1270:                    if (file.isClassStub()
1271:                            || (stripDirectories && file.isDirectory())) {
1272:                        i.remove();
1273:                    }
1274:                }
1275:
1276:                // Sort the remaining non-class files.
1277:                // We sort them by file type.
1278:                // This keeps files of similar format near each other.
1279:                // Put class files at the end, keeping their fixed order.
1280:                // Be sure the JAR file's required manifest stays at the front. (4893051)
1281:                Collections.sort(files, new Comparator() {
1282:                    public int compare(Object o0, Object o1) {
1283:                        File r0 = (File) o0;
1284:                        File r1 = (File) o1;
1285:                        // Get the file name.
1286:                        String f0 = r0.nameString;
1287:                        String f1 = r1.nameString;
1288:                        if (f0.equals(f1))
1289:                            return 0;
1290:                        if (JarFile.MANIFEST_NAME.equals(f0))
1291:                            return 0 - 1;
1292:                        if (JarFile.MANIFEST_NAME.equals(f1))
1293:                            return 1 - 0;
1294:                        // Extract file basename.
1295:                        String n0 = f0.substring(1 + f0.lastIndexOf('/'));
1296:                        String n1 = f1.substring(1 + f1.lastIndexOf('/'));
1297:                        // Extract basename extension.
1298:                        String x0 = n0.substring(1 + n0.lastIndexOf('.'));
1299:                        String x1 = n1.substring(1 + n1.lastIndexOf('.'));
1300:                        int r;
1301:                        // Primary sort key is file extension.
1302:                        r = x0.compareTo(x1);
1303:                        if (r != 0)
1304:                            return r;
1305:                        r = f0.compareTo(f1);
1306:                        return r;
1307:                    }
1308:                });
1309:
1310:                // Add back the class stubs after sorting, before trimStubs.
1311:                files.addAll(stubs);
1312:            }
1313:
1314:            void trimStubs() {
1315:                // Restore enough non-trivial stubs to carry the needed class modtimes.
1316:                for (ListIterator i = files.listIterator(files.size()); i
1317:                        .hasPrevious();) {
1318:                    File file = (File) i.previous();
1319:                    if (!file.isTrivialClassStub()) {
1320:                        if (verbose > 1)
1321:                            Utils.log.fine("Keeping last non-trivial " + file);
1322:                        break;
1323:                    }
1324:                    if (verbose > 2)
1325:                        Utils.log.fine("Removing trivial " + file);
1326:                    i.remove();
1327:                }
1328:
1329:                if (verbose > 0) {
1330:                    Utils.log.info("Transmitting " + files.size()
1331:                            + " files, including per-file data for "
1332:                            + getClassStubs().size() + " classes out of "
1333:                            + classes.size());
1334:                }
1335:            }
1336:
1337:            // Use this before writing the package file.
1338:            void buildGlobalConstantPool(Set requiredEntries) {
1339:                if (verbose > 1)
1340:                    Utils.log.fine("Checking for unused CP entries");
1341:                requiredEntries.add(getRefString("")); // uconditionally present
1342:                visitRefs(VRM_PACKAGE, requiredEntries);
1343:                ConstantPool.completeReferencesIn(requiredEntries, false);
1344:                if (verbose > 1)
1345:                    Utils.log.fine("Sorting CP entries");
1346:                Index cpAllU = ConstantPool.makeIndex("unsorted",
1347:                        requiredEntries);
1348:                Index[] byTagU = ConstantPool.partitionByTag(cpAllU);
1349:                for (int i = 0; i < ConstantPool.TAGS_IN_ORDER.length; i++) {
1350:                    byte tag = ConstantPool.TAGS_IN_ORDER[i];
1351:                    // Work on all entries of a given kind.
1352:                    Index ix = byTagU[tag];
1353:                    if (ix == null)
1354:                        continue;
1355:                    ConstantPool.sort(ix);
1356:                    cp.initIndexByTag(tag, ix);
1357:                    byTagU[tag] = null; // done with it
1358:                }
1359:                for (int i = 0; i < byTagU.length; i++) {
1360:                    assert (byTagU[i] == null); // all consumed
1361:                }
1362:                for (int i = 0; i < ConstantPool.TAGS_IN_ORDER.length; i++) {
1363:                    byte tag = ConstantPool.TAGS_IN_ORDER[i];
1364:                    Index ix = cp.getIndexByTag(tag);
1365:                    assert (ix.assertIsSorted());
1366:                    if (verbose > 2)
1367:                        Utils.log.fine(ix.dumpString());
1368:                }
1369:            }
1370:
1371:            // Use this before writing the class files.
1372:            void ensureAllClassFiles() {
1373:                HashSet fileSet = new HashSet(files);
1374:                for (Iterator i = classes.iterator(); i.hasNext();) {
1375:                    Class cls = (Class) i.next();
1376:                    // Add to the end of ths list:
1377:                    if (!fileSet.contains(cls.file))
1378:                        files.add(cls.file);
1379:                }
1380:            }
1381:
1382:            static final List noObjects = Arrays.asList(new Object[0]);
1383:            static final List noFields = Arrays.asList(new Class.Field[0]);
1384:            static final List noMethods = Arrays.asList(new Class.Method[0]);
1385:            static final List noInnerClasses = Arrays.asList(new InnerClass[0]);
1386:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.