Source Code Cross Referenced for Attribute.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 2003-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.io.*;
0029:        import java.util.*;
0030:        import com.sun.java.util.jar.pack.Package.Class;
0031:        import com.sun.java.util.jar.pack.ConstantPool.*;
0032:
0033:        /**
0034:         * Represents an attribute in a class-file.
0035:         * Takes care to remember where constant pool indexes occur.
0036:         * Implements the "little language" of Pack200 for describing
0037:         * attribute layouts.
0038:         * @author John Rose
0039:         * @version 1.27, 05/05/07
0040:         */
0041:        class Attribute implements  Comparable, Constants {
0042:            // Attribute instance fields.
0043:
0044:            Layout def; // the name and format of this attr
0045:            byte[] bytes; // the actual bytes
0046:            Object fixups; // reference relocations, if any are required
0047:
0048:            public String name() {
0049:                return def.name();
0050:            }
0051:
0052:            public Layout layout() {
0053:                return def;
0054:            }
0055:
0056:            public byte[] bytes() {
0057:                return bytes;
0058:            }
0059:
0060:            public int size() {
0061:                return bytes.length;
0062:            }
0063:
0064:            public Entry getNameRef() {
0065:                return def.getNameRef();
0066:            }
0067:
0068:            private Attribute(Attribute old) {
0069:                this .def = old.def;
0070:                this .bytes = old.bytes;
0071:                this .fixups = old.fixups;
0072:            }
0073:
0074:            public Attribute(Layout def, byte[] bytes, Object fixups) {
0075:                this .def = def;
0076:                this .bytes = bytes;
0077:                this .fixups = fixups;
0078:                Fixups.setBytes(fixups, bytes);
0079:            }
0080:
0081:            public Attribute(Layout def, byte[] bytes) {
0082:                this (def, bytes, null);
0083:            }
0084:
0085:            public Attribute addContent(byte[] bytes, Object fixups) {
0086:                assert (isCanonical());
0087:                if (bytes.length == 0 && fixups == null)
0088:                    return this ;
0089:                Attribute res = new Attribute(this );
0090:                res.bytes = bytes;
0091:                res.fixups = fixups;
0092:                Fixups.setBytes(fixups, bytes);
0093:                return res;
0094:            }
0095:
0096:            public Attribute addContent(byte[] bytes) {
0097:                return addContent(bytes, null);
0098:            }
0099:
0100:            public void finishRefs(Index ix) {
0101:                if (fixups != null) {
0102:                    Fixups.finishRefs(fixups, bytes, ix);
0103:                    fixups = null;
0104:                }
0105:            }
0106:
0107:            public boolean isCanonical() {
0108:                return this  == def.canon;
0109:            }
0110:
0111:            public int compareTo(Object o) {
0112:                Attribute that = (Attribute) o;
0113:                return this .def.compareTo(that.def);
0114:            }
0115:
0116:            static private final byte[] noBytes = {};
0117:            static private final HashMap canonLists = new HashMap();
0118:            static private final HashMap attributes = new HashMap();
0119:            static private final HashMap standardDefs = new HashMap();
0120:
0121:            // Canonicalized lists of trivial attrs (Deprecated, etc.)
0122:            // are used by trimToSize, in order to reduce footprint
0123:            // of some common cases.  (Note that Code attributes are
0124:            // always zero size.)
0125:            public static List getCanonList(List al) {
0126:                synchronized (canonLists) {
0127:                    List cl = (List) canonLists.get(al);
0128:                    if (cl == null) {
0129:                        cl = new ArrayList(al.size());
0130:                        cl.addAll(al);
0131:                        cl = Collections.unmodifiableList(cl);
0132:                        canonLists.put(al, cl);
0133:                    }
0134:                    return cl;
0135:                }
0136:            }
0137:
0138:            // Find the canonical empty attribute with the given ctype, name, layout.
0139:            public static Attribute find(int ctype, String name, String layout) {
0140:                Layout key = Layout.makeKey(ctype, name, layout);
0141:                synchronized (attributes) {
0142:                    Attribute a = (Attribute) attributes.get(key);
0143:                    if (a == null) {
0144:                        a = new Layout(ctype, name, layout).canonicalInstance();
0145:                        attributes.put(key, a);
0146:                    }
0147:                    return a;
0148:                }
0149:            }
0150:
0151:            public static Object keyForLookup(int ctype, String name) {
0152:                return Layout.makeKey(ctype, name);
0153:            }
0154:
0155:            // Find canonical empty attribute with given ctype and name,
0156:            // and with the standard layout.
0157:            public static Attribute lookup(Map defs, int ctype, String name) {
0158:                if (defs == null)
0159:                    defs = standardDefs;
0160:                return (Attribute) defs.get(Layout.makeKey(ctype, name));
0161:            }
0162:
0163:            public static Attribute define(Map defs, int ctype, String name,
0164:                    String layout) {
0165:                Attribute a = find(ctype, name, layout);
0166:                defs.put(Layout.makeKey(ctype, name), a);
0167:                return a;
0168:            }
0169:
0170:            static {
0171:                Map sd = standardDefs;
0172:                define(sd, ATTR_CONTEXT_CLASS, "Signature", "RSH");
0173:                define(sd, ATTR_CONTEXT_CLASS, "Synthetic", "");
0174:                define(sd, ATTR_CONTEXT_CLASS, "Deprecated", "");
0175:                define(sd, ATTR_CONTEXT_CLASS, "SourceFile", "RUH");
0176:                define(sd, ATTR_CONTEXT_CLASS, "EnclosingMethod", "RCHRDNH");
0177:                define(sd, ATTR_CONTEXT_CLASS, "InnerClasses",
0178:                        "NH[RCHRCNHRUNHFH]");
0179:
0180:                define(sd, ATTR_CONTEXT_FIELD, "Signature", "RSH");
0181:                define(sd, ATTR_CONTEXT_FIELD, "Synthetic", "");
0182:                define(sd, ATTR_CONTEXT_FIELD, "Deprecated", "");
0183:                define(sd, ATTR_CONTEXT_FIELD, "ConstantValue", "KQH");
0184:
0185:                define(sd, ATTR_CONTEXT_METHOD, "Signature", "RSH");
0186:                define(sd, ATTR_CONTEXT_METHOD, "Synthetic", "");
0187:                define(sd, ATTR_CONTEXT_METHOD, "Deprecated", "");
0188:                define(sd, ATTR_CONTEXT_METHOD, "Exceptions", "NH[RCH]");
0189:                //define(sd, ATTR_CONTEXT_METHOD, "Code", "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]");
0190:
0191:                define(sd, ATTR_CONTEXT_CODE, "StackMapTable", ("[NH[(1)]]"
0192:                        + "[TB" + "(64-127)[(2)]" + "(247)[(1)(2)]"
0193:                        + "(248-251)[(1)]" + "(252)[(1)(2)]"
0194:                        + "(253)[(1)(2)(2)]" + "(254)[(1)(2)(2)(2)]"
0195:                        + "(255)[(1)NH[(2)]NH[(2)]]" + "()[]" + "]" + "[H]"
0196:                        + "[TB(7)[RCH](8)[PH]()[]]"));
0197:
0198:                define(sd, ATTR_CONTEXT_CODE, "LineNumberTable", "NH[PHH]");
0199:                define(sd, ATTR_CONTEXT_CODE, "LocalVariableTable",
0200:                        "NH[PHOHRUHRSHH]");
0201:                define(sd, ATTR_CONTEXT_CODE, "LocalVariableTypeTable",
0202:                        "NH[PHOHRUHRSHH]");
0203:                //define(sd, ATTR_CONTEXT_CODE, "CharacterRangeTable", "NH[PHPOHIIH]");
0204:                //define(sd, ATTR_CONTEXT_CODE, "CoverageTable", "NH[PHHII]");
0205:
0206:                // Note:  Code and InnerClasses are special-cased elsewhere.
0207:                // Their layout specs. are given here for completeness.
0208:                // The Code spec is incomplete, in that it does not distinguish
0209:                // bytecode bytes or locate CP references.
0210:            }
0211:
0212:            // Metadata.
0213:            //
0214:            // We define metadata using similar layouts
0215:            // for all five kinds of metadata attributes.
0216:            // 
0217:            // Regular annotations are a counted list of [RSHNH[RUH(1)]][...]
0218:            //   pack.method.attribute.RuntimeVisibleAnnotations=[NH[(1)]][RSHNH[RUH(1)]][TB...]
0219:            //
0220:            // Parameter annotations are a counted list of regular annotations.
0221:            //   pack.method.attribute.RuntimeVisibleParameterAnnotations=[NH[(1)]][NH[(1)]][RSHNH[RUH(1)]][TB...]
0222:            //
0223:            // RuntimeInvisible annotations are defined similarly...
0224:            // Non-method annotations are defined similarly...
0225:            //
0226:            // Annotation are a simple tagged value [TB...]
0227:            //   pack.attribute.method.AnnotationDefault=[TB...]
0228:            //
0229:            static {
0230:                String mdLayouts[] = {
0231:                        Attribute
0232:                                .normalizeLayoutString(""
0233:                                        + "\n  # parameter_annotations :="
0234:                                        + "\n  [ NB[(1)] ]     # forward call to annotations"),
0235:                        Attribute
0236:                                .normalizeLayoutString(""
0237:                                        + "\n  # annotations :="
0238:                                        + "\n  [ NH[(1)] ]     # forward call to annotation"
0239:                                        + "\n  "
0240:                                        + "\n  # annotation :="
0241:                                        + "\n  [RSH"
0242:                                        + "\n    NH[RUH (1)]   # forward call to value"
0243:                                        + "\n    ]"),
0244:                        Attribute
0245:                                .normalizeLayoutString(""
0246:                                        + "\n  # value :="
0247:                                        + "\n  [TB # Callable 2 encodes one tagged value."
0248:                                        + "\n    (\\B,\\C,\\I,\\S,\\Z)[KIH]"
0249:                                        + "\n    (\\D)[KDH]"
0250:                                        + "\n    (\\F)[KFH]"
0251:                                        + "\n    (\\J)[KJH]"
0252:                                        + "\n    (\\c)[RSH]"
0253:                                        + "\n    (\\e)[RSH RUH]"
0254:                                        + "\n    (\\s)[RUH]"
0255:                                        + "\n    (\\[)[NH[(0)]] # backward self-call to value"
0256:                                        + "\n    (\\@)[RSH NH[RUH (0)]] # backward self-call to value"
0257:                                        + "\n    ()[] ]") };
0258:                Map sd = standardDefs;
0259:                String defaultLayout = mdLayouts[2];
0260:                String annotationsLayout = mdLayouts[1] + mdLayouts[2];
0261:                String paramsLayout = mdLayouts[0] + annotationsLayout;
0262:                for (int ctype = 0; ctype < ATTR_CONTEXT_LIMIT; ctype++) {
0263:                    if (ctype == ATTR_CONTEXT_CODE)
0264:                        continue;
0265:                    define(sd, ctype, "RuntimeVisibleAnnotations",
0266:                            annotationsLayout);
0267:                    define(sd, ctype, "RuntimeInvisibleAnnotations",
0268:                            annotationsLayout);
0269:                    if (ctype == ATTR_CONTEXT_METHOD) {
0270:                        define(sd, ctype, "RuntimeVisibleParameterAnnotations",
0271:                                paramsLayout);
0272:                        define(sd, ctype,
0273:                                "RuntimeInvisibleParameterAnnotations",
0274:                                paramsLayout);
0275:                        define(sd, ctype, "AnnotationDefault", defaultLayout);
0276:                    }
0277:                }
0278:            }
0279:
0280:            public static String contextName(int ctype) {
0281:                switch (ctype) {
0282:                case ATTR_CONTEXT_CLASS:
0283:                    return "class";
0284:                case ATTR_CONTEXT_FIELD:
0285:                    return "field";
0286:                case ATTR_CONTEXT_METHOD:
0287:                    return "method";
0288:                case ATTR_CONTEXT_CODE:
0289:                    return "code";
0290:                }
0291:                return null;
0292:            }
0293:
0294:            public static Map getStandardDefs() {
0295:                return new HashMap(standardDefs);
0296:            }
0297:
0298:            /** Base class for any attributed object (Class, Field, Method, Code).
0299:             *  Flags are included because they are used to help transmit the
0300:             *  presence of attributes.  That is, flags are a mix of modifier
0301:             *  bits and attribute indicators.
0302:             */
0303:            public static abstract class Holder {
0304:
0305:                // We need this abstract method to interpret embedded CP refs.
0306:                protected abstract Entry[] getCPMap();
0307:
0308:                protected int flags; // defined here for convenience
0309:                protected List attributes;
0310:
0311:                public int attributeSize() {
0312:                    return (attributes == null) ? 0 : attributes.size();
0313:                }
0314:
0315:                public void trimToSize() {
0316:                    if (attributes == null) {
0317:                        return;
0318:                    }
0319:                    if (attributes.size() == 0) {
0320:                        attributes = null;
0321:                        return;
0322:                    }
0323:                    if (attributes instanceof  ArrayList) {
0324:                        ArrayList al = (ArrayList) attributes;
0325:                        al.trimToSize();
0326:                        boolean allCanon = true;
0327:                        for (Iterator i = al.iterator(); i.hasNext();) {
0328:                            Attribute a = (Attribute) i.next();
0329:                            if (!a.isCanonical()) {
0330:                                allCanon = false;
0331:                            }
0332:                            if (a.fixups != null) {
0333:                                assert (!a.isCanonical());
0334:                                a.fixups = Fixups.trimToSize(a.fixups);
0335:                            }
0336:                        }
0337:                        if (allCanon) {
0338:                            // Replace private writable attribute list
0339:                            // with only trivial entries by public unique
0340:                            // immutable attribute list with the same entries.
0341:                            attributes = getCanonList(al);
0342:                        }
0343:                    }
0344:                }
0345:
0346:                public void addAttribute(Attribute a) {
0347:                    if (attributes == null)
0348:                        attributes = new ArrayList(3);
0349:                    else if (!(attributes instanceof  ArrayList))
0350:                        attributes = new ArrayList(attributes); // unfreeze it
0351:                    attributes.add(a);
0352:                }
0353:
0354:                public Attribute removeAttribute(Attribute a) {
0355:                    if (attributes == null)
0356:                        return null;
0357:                    if (!attributes.contains(a))
0358:                        return null;
0359:                    if (!(attributes instanceof  ArrayList))
0360:                        attributes = new ArrayList(attributes); // unfreeze it
0361:                    attributes.remove(a);
0362:                    return a;
0363:                }
0364:
0365:                public Attribute getAttribute(int n) {
0366:                    return (Attribute) attributes.get(n);
0367:                }
0368:
0369:                protected void visitRefs(int mode, Collection refs) {
0370:                    if (attributes == null)
0371:                        return;
0372:                    for (Iterator i = attributes.iterator(); i.hasNext();) {
0373:                        Attribute a = (Attribute) i.next();
0374:                        a.visitRefs(this , mode, refs);
0375:                    }
0376:                }
0377:
0378:                static final List noAttributes = Arrays.asList(new Object[0]);
0379:
0380:                public List getAttributes() {
0381:                    if (attributes == null)
0382:                        return noAttributes;
0383:                    return attributes;
0384:                }
0385:
0386:                public void setAttributes(List attrList) {
0387:                    if (attrList.isEmpty())
0388:                        attributes = null;
0389:                    else
0390:                        attributes = attrList;
0391:                }
0392:
0393:                public Attribute getAttribute(String attrName) {
0394:                    if (attributes == null)
0395:                        return null;
0396:                    for (Iterator i = attributes.iterator(); i.hasNext();) {
0397:                        Attribute a = (Attribute) i.next();
0398:                        if (a.name().equals(attrName))
0399:                            return a;
0400:                    }
0401:                    return null;
0402:                }
0403:
0404:                public Attribute getAttribute(Layout attrDef) {
0405:                    if (attributes == null)
0406:                        return null;
0407:                    for (Iterator i = attributes.iterator(); i.hasNext();) {
0408:                        Attribute a = (Attribute) i.next();
0409:                        if (a.layout() == attrDef)
0410:                            return a;
0411:                    }
0412:                    return null;
0413:                }
0414:
0415:                public Attribute removeAttribute(String attrName) {
0416:                    return removeAttribute(getAttribute(attrName));
0417:                }
0418:
0419:                public Attribute removeAttribute(Layout attrDef) {
0420:                    return removeAttribute(getAttribute(attrDef));
0421:                }
0422:
0423:                public void strip(String attrName) {
0424:                    removeAttribute(getAttribute(attrName));
0425:                }
0426:            }
0427:
0428:            // Lightweight interface to hide details of band structure.
0429:            // Also used for testing.
0430:            public static abstract class ValueStream {
0431:                public int getInt(int bandIndex) {
0432:                    throw undef();
0433:                }
0434:
0435:                public void putInt(int bandIndex, int value) {
0436:                    throw undef();
0437:                }
0438:
0439:                public Entry getRef(int bandIndex) {
0440:                    throw undef();
0441:                }
0442:
0443:                public void putRef(int bandIndex, Entry ref) {
0444:                    throw undef();
0445:                }
0446:
0447:                // Note:  decodeBCI goes w/ getInt/Ref; encodeBCI goes w/ putInt/Ref
0448:                public int decodeBCI(int bciCode) {
0449:                    throw undef();
0450:                }
0451:
0452:                public int encodeBCI(int bci) {
0453:                    throw undef();
0454:                }
0455:
0456:                public void noteBackCall(int whichCallable) { /* ignore by default */
0457:                }
0458:
0459:                private RuntimeException undef() {
0460:                    return new UnsupportedOperationException(
0461:                            "ValueStream method");
0462:                }
0463:            }
0464:
0465:            // Element kinds:
0466:            static final byte EK_INT = 1; // B H I SH etc.
0467:            static final byte EK_BCI = 2; // PH POH etc.
0468:            static final byte EK_BCO = 3; // OH etc.
0469:            static final byte EK_FLAG = 4; // FH etc.
0470:            static final byte EK_REPL = 5; // NH[...] etc.
0471:            static final byte EK_REF = 6; // RUH, RUNH, KQH, etc.
0472:            static final byte EK_UN = 7; // TB(...)[...] etc.
0473:            static final byte EK_CASE = 8; // (...)[...] etc.
0474:            static final byte EK_CALL = 9; // (0), (1), etc.
0475:            static final byte EK_CBLE = 10; // [...][...] etc.
0476:            static final byte EF_SIGN = 1 << 0; // INT is signed
0477:            static final byte EF_DELTA = 1 << 1; // BCI/BCI value is diff'ed w/ previous
0478:            static final byte EF_NULL = 1 << 2; // null REF is expected/allowed
0479:            static final byte EF_BACK = 1 << 3; // call, callable, case is backward
0480:            static final int NO_BAND_INDEX = -1;
0481:
0482:            /** A "class" of attributes, characterized by a context-type, name
0483:             *  and format.  The formats are specified in a "little language".
0484:             */
0485:            public static class Layout implements  Comparable {
0486:                int ctype; // attribute context type, e.g., ATTR_CONTEXT_CODE
0487:                String name; // name of attribute
0488:                boolean hasRefs; // this kind of attr contains CP refs?
0489:                String layout; // layout specification
0490:                int bandCount; // total number of elems
0491:                Element[] elems; // tokenization of layout
0492:                Attribute canon; // canonical instance of this layout
0493:
0494:                public int ctype() {
0495:                    return ctype;
0496:                }
0497:
0498:                public String name() {
0499:                    return name;
0500:                }
0501:
0502:                public String layout() {
0503:                    return layout;
0504:                }
0505:
0506:                public Attribute canonicalInstance() {
0507:                    return canon;
0508:                }
0509:
0510:                // Cache of name reference.
0511:                private Entry nameRef; // name, for use by visitRefs
0512:
0513:                public Entry getNameRef() {
0514:                    Entry nameRef = this .nameRef;
0515:                    if (nameRef == null) {
0516:                        this .nameRef = nameRef = ConstantPool
0517:                                .getUtf8Entry(name());
0518:                    }
0519:                    return nameRef;
0520:                }
0521:
0522:                public boolean isEmpty() {
0523:                    return layout == "";
0524:                }
0525:
0526:                public Layout(int ctype, String name, String layout) {
0527:                    this .ctype = ctype;
0528:                    this .name = name.intern();
0529:                    this .layout = layout.intern();
0530:                    assert (ctype < ATTR_CONTEXT_LIMIT);
0531:                    boolean hasCallables = layout.startsWith("[");
0532:                    try {
0533:                        if (!hasCallables) {
0534:                            this .elems = tokenizeLayout(this , -1, layout);
0535:                        } else {
0536:                            String[] bodies = splitBodies(layout);
0537:                            // Make the callables now, so they can be linked immediately.
0538:                            Element[] elems = new Element[bodies.length];
0539:                            this .elems = elems;
0540:                            for (int i = 0; i < elems.length; i++) {
0541:                                Element ce = this .new Element();
0542:                                ce.kind = EK_CBLE;
0543:                                ce.removeBand();
0544:                                ce.bandIndex = NO_BAND_INDEX;
0545:                                ce.layout = bodies[i];
0546:                                elems[i] = ce;
0547:                            }
0548:                            // Next fill them in.
0549:                            for (int i = 0; i < elems.length; i++) {
0550:                                Element ce = elems[i];
0551:                                ce.body = tokenizeLayout(this , i, bodies[i]);
0552:                            }
0553:                            //System.out.println(Arrays.asList(elems));
0554:                        }
0555:                    } catch (StringIndexOutOfBoundsException ee) {
0556:                        // simplest way to catch syntax errors...
0557:                        throw new RuntimeException("Bad attribute layout: "
0558:                                + layout, ee);
0559:                    }
0560:                    // Some uses do not make a fresh one for each occurrence.
0561:                    // For example, if layout == "", we only need one attr to share.
0562:                    canon = new Attribute(this , noBytes);
0563:                }
0564:
0565:                private Layout() {
0566:                }
0567:
0568:                static Layout makeKey(int ctype, String name, String layout) {
0569:                    Layout def = new Layout();
0570:                    def.ctype = ctype;
0571:                    def.name = name.intern();
0572:                    def.layout = layout.intern();
0573:                    assert (ctype < ATTR_CONTEXT_LIMIT);
0574:                    return def;
0575:                }
0576:
0577:                static Layout makeKey(int ctype, String name) {
0578:                    return makeKey(ctype, name, "");
0579:                }
0580:
0581:                public Attribute addContent(byte[] bytes, Object fixups) {
0582:                    return canon.addContent(bytes, fixups);
0583:                }
0584:
0585:                public Attribute addContent(byte[] bytes) {
0586:                    return canon.addContent(bytes, null);
0587:                }
0588:
0589:                public boolean equals(Object x) {
0590:                    return x instanceof  Layout && equals((Layout) x);
0591:                }
0592:
0593:                public boolean equals(Layout that) {
0594:                    return this .name == that.name && this .layout == that.layout
0595:                            && this .ctype == that.ctype;
0596:                }
0597:
0598:                public int hashCode() {
0599:                    return (((17 + name.hashCode()) * 37 + layout.hashCode()) * 37 + ctype);
0600:                }
0601:
0602:                public int compareTo(Object o) {
0603:                    Layout that = (Layout) o;
0604:                    int r;
0605:                    r = this .name.compareTo(that.name);
0606:                    if (r != 0)
0607:                        return r;
0608:                    r = this .layout.compareTo(that.layout);
0609:                    if (r != 0)
0610:                        return r;
0611:                    return this .ctype - that.ctype;
0612:                }
0613:
0614:                public String toString() {
0615:                    String str = contextName(ctype) + "." + name + "[" + layout
0616:                            + "]";
0617:                    // If -ea, print out more informative strings!
0618:                    assert ((str = stringForDebug()) != null);
0619:                    return str;
0620:                }
0621:
0622:                private String stringForDebug() {
0623:                    return contextName(ctype) + "." + name
0624:                            + Arrays.asList(elems);
0625:                }
0626:
0627:                public class Element {
0628:                    String layout; // spelling in the little language
0629:                    byte flags; // EF_SIGN, etc.
0630:                    byte kind; // EK_UINT, etc.
0631:                    byte len; // scalar length of element
0632:                    byte refKind; // CONSTANT_String, etc.
0633:                    int bandIndex; // which band does this element govern?
0634:                    int value; // extra parameter
0635:                    Element[] body; // extra data (for replications, unions, calls)
0636:
0637:                    boolean flagTest(byte mask) {
0638:                        return (flags & mask) != 0;
0639:                    }
0640:
0641:                    Element() {
0642:                        bandIndex = bandCount++;
0643:                    }
0644:
0645:                    void removeBand() {
0646:                        --bandCount;
0647:                        assert (bandIndex == bandCount);
0648:                        bandIndex = NO_BAND_INDEX;
0649:                    }
0650:
0651:                    public boolean hasBand() {
0652:                        return bandIndex >= 0;
0653:                    }
0654:
0655:                    public String toString() {
0656:                        String str = layout;
0657:                        // If -ea, print out more informative strings!
0658:                        assert ((str = stringForDebug()) != null);
0659:                        return str;
0660:                    }
0661:
0662:                    private String stringForDebug() {
0663:                        Element[] body = this .body;
0664:                        switch (kind) {
0665:                        case EK_CALL:
0666:                            body = null;
0667:                            break;
0668:                        case EK_CASE:
0669:                            if (flagTest(EF_BACK))
0670:                                body = null;
0671:                            break;
0672:                        }
0673:                        return layout
0674:                                + (!hasBand() ? "" : "#" + bandIndex)
0675:                                + "<"
0676:                                + (flags == 0 ? "" : "" + flags)
0677:                                + kind
0678:                                + len
0679:                                + (refKind == 0 ? "" : "" + refKind)
0680:                                + ">"
0681:                                + (value == 0 ? "" : "(" + value + ")")
0682:                                + (body == null ? "" : "" + Arrays.asList(body));
0683:                    }
0684:                }
0685:
0686:                public boolean hasCallables() {
0687:                    return (elems.length > 0 && elems[0].kind == EK_CBLE);
0688:                }
0689:
0690:                static private final Element[] noElems = {};
0691:
0692:                public Element[] getCallables() {
0693:                    if (hasCallables())
0694:                        return elems;
0695:                    else
0696:                        return noElems; // no callables at all
0697:                }
0698:
0699:                public Element[] getEntryPoint() {
0700:                    if (hasCallables())
0701:                        return elems[0].body; // body of first callable
0702:                    else
0703:                        return elems; // no callables; whole body
0704:                }
0705:
0706:                /** Return a sequence of tokens from the given attribute bytes.
0707:                 *  Sequence elements will be 1-1 correspondent with my layout tokens.
0708:                 */
0709:                public void parse(Holder holder, byte[] bytes, int pos,
0710:                        int len, ValueStream out) {
0711:                    int end = parseUsing(getEntryPoint(), holder, bytes, pos,
0712:                            len, out);
0713:                    if (end != pos + len)
0714:                        throw new InternalError("layout parsed " + (end - pos)
0715:                                + " out of " + len + " bytes");
0716:                }
0717:
0718:                /** Given a sequence of tokens, return the attribute bytes.
0719:                 *  Sequence elements must be 1-1 correspondent with my layout tokens.
0720:                 *  The returned object is a cookie for Fixups.finishRefs, which
0721:                 *  must be used to harden any references into integer indexes.
0722:                 */
0723:                public Object unparse(ValueStream in, ByteArrayOutputStream out) {
0724:                    Object[] fixups = { null };
0725:                    unparseUsing(getEntryPoint(), fixups, in, out);
0726:                    return fixups[0]; // return ref-bearing cookie, if any
0727:                }
0728:
0729:                public String layoutForPackageMajver(int majver) {
0730:                    if (majver <= JAVA5_PACKAGE_MAJOR_VERSION) {
0731:                        // Disallow layout syntax in the oldest protocol version.
0732:                        return expandCaseDashNotation(layout);
0733:                    }
0734:                    return layout;
0735:                }
0736:            }
0737:
0738:            public static class FormatException extends IOException {
0739:                private int ctype;
0740:                private String name;
0741:                String layout;
0742:
0743:                public FormatException(String message, int ctype, String name,
0744:                        String layout) {
0745:                    super (ATTR_CONTEXT_NAME[ctype] + "." + name
0746:                            + (message == null ? "" : (": " + message)));
0747:                    this .ctype = ctype;
0748:                    this .name = name;
0749:                    this .layout = layout;
0750:                }
0751:
0752:                public FormatException(String message, int ctype, String name) {
0753:                    this (message, ctype, name, null);
0754:                }
0755:            }
0756:
0757:            void visitRefs(Holder holder, int mode, final Collection refs) {
0758:                if (mode == VRM_CLASSIC) {
0759:                    refs.add(getNameRef());
0760:                }
0761:                // else the name is owned by the layout, and is processed elsewhere
0762:                if (bytes.length == 0)
0763:                    return; // quick exit
0764:                if (!def.hasRefs)
0765:                    return; // quick exit
0766:                if (fixups != null) {
0767:                    Fixups.visitRefs(fixups, refs);
0768:                    return;
0769:                }
0770:                // References (to a local cpMap) are embedded in the bytes.
0771:                def.parse(holder, bytes, 0, bytes.length, new ValueStream() {
0772:                    public void putInt(int bandIndex, int value) {
0773:                    }
0774:
0775:                    public void putRef(int bandIndex, Entry ref) {
0776:                        refs.add(ref);
0777:                    }
0778:
0779:                    public int encodeBCI(int bci) {
0780:                        return bci;
0781:                    }
0782:                });
0783:            }
0784:
0785:            public void parse(Holder holder, byte[] bytes, int pos, int len,
0786:                    ValueStream out) {
0787:                def.parse(holder, bytes, pos, len, out);
0788:            }
0789:
0790:            public Object unparse(ValueStream in, ByteArrayOutputStream out) {
0791:                return def.unparse(in, out);
0792:            }
0793:
0794:            public String toString() {
0795:                return def + "{" + (bytes == null ? -1 : size()) + "}"
0796:                        + (fixups == null ? "" : fixups.toString());
0797:            }
0798:
0799:            /** Remove any informal "pretty printing" from the layout string.
0800:             *  Removes blanks and control chars.
0801:             *  Removes '#' comments (to end of line).
0802:             *  Replaces '\c' by the decimal code of the character c.
0803:             *  Replaces '0xNNN' by the decimal code of the hex number NNN.
0804:             */
0805:            static public String normalizeLayoutString(String layout) {
0806:                StringBuffer buf = new StringBuffer();
0807:                for (int i = 0, len = layout.length(); i < len;) {
0808:                    char ch = layout.charAt(i++);
0809:                    if (ch <= ' ') {
0810:                        // Skip whitespace and control chars
0811:                        continue;
0812:                    } else if (ch == '#') {
0813:                        // Skip to end of line.
0814:                        int end1 = layout.indexOf('\n', i);
0815:                        int end2 = layout.indexOf('\r', i);
0816:                        if (end1 < 0)
0817:                            end1 = len;
0818:                        if (end2 < 0)
0819:                            end2 = len;
0820:                        i = Math.min(end1, end2);
0821:                    } else if (ch == '\\') {
0822:                        // Map a character reference to its decimal code.
0823:                        buf.append((int) layout.charAt(i++));
0824:                    } else if (ch == '0' && layout.startsWith("0x", i - 1)) {
0825:                        // Map a hex numeral to its decimal code.
0826:                        int start = i - 1;
0827:                        int end = start + 2;
0828:                        while (end < len) {
0829:                            int dig = layout.charAt(end);
0830:                            if ((dig >= '0' && dig <= '9')
0831:                                    || (dig >= 'a' && dig <= 'f'))
0832:                                ++end;
0833:                            else
0834:                                break;
0835:                        }
0836:                        if (end > start) {
0837:                            String num = layout.substring(start, end);
0838:                            buf.append(Integer.decode(num));
0839:                            i = end;
0840:                        } else {
0841:                            buf.append(ch);
0842:                        }
0843:                    } else {
0844:                        buf.append(ch);
0845:                    }
0846:                }
0847:                String result = buf.toString();
0848:                if (false && !result.equals(layout)) {
0849:                    Utils.log.info("Normalizing layout string");
0850:                    Utils.log.info("    From: " + layout);
0851:                    Utils.log.info("    To:   " + result);
0852:                }
0853:                return result;
0854:            }
0855:
0856:            /// Subroutines for parsing and unparsing:
0857:
0858:            /** Parse the attribute layout language.
0859:            <pre>
0860:            attribute_layout:
0861:                ( layout_element )* | ( callable )+
0862:            layout_element:
0863:                ( integral | replication | union | call | reference )
0864:
0865:            callable:
0866:                '[' body ']'
0867:            body:
0868:                ( layout_element )+
0869:
0870:            integral:
0871:                ( unsigned_int | signed_int | bc_index | bc_offset | flag )
0872:            unsigned_int:
0873:                uint_type
0874:            signed_int:
0875:                'S' uint_type
0876:            any_int:
0877:                ( unsigned_int | signed_int )
0878:            bc_index:
0879:                ( 'P' uint_type | 'PO' uint_type )
0880:            bc_offset:
0881:                'O' any_int
0882:            flag:
0883:                'F' uint_type
0884:            uint_type:
0885:                ( 'B' | 'H' | 'I' | 'V' )
0886:
0887:            replication:
0888:                'N' uint_type '[' body ']'
0889:
0890:            union:
0891:                'T' any_int (union_case)* '(' ')' '[' (body)? ']'
0892:            union_case:
0893:                '(' union_case_tag (',' union_case_tag)* ')' '[' (body)? ']'
0894:            union_case_tag:
0895:                ( numeral | numeral '-' numeral )
0896:            call:
0897:                '(' numeral ')'
0898:
0899:            reference:
0900:                reference_type ( 'N' )? uint_type
0901:            reference_type:
0902:                ( constant_ref | schema_ref | utf8_ref | untyped_ref )
0903:            constant_ref:
0904:                ( 'KI' | 'KJ' | 'KF' | 'KD' | 'KS' | 'KQ' )
0905:            schema_ref:
0906:                ( 'RC' | 'RS' | 'RD' | 'RF' | 'RM' | 'RI' )
0907:            utf8_ref:
0908:                'RU'
0909:            untyped_ref:
0910:                'RQ'
0911:
0912:            numeral:
0913:                '(' ('-')? (digit)+ ')'
0914:            digit:
0915:                ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
0916:            </pre>
0917:             */
0918:            static//private
0919:            Layout.Element[] tokenizeLayout(Layout self, int curCble,
0920:                    String layout) {
0921:                ArrayList col = new ArrayList(layout.length());
0922:                tokenizeLayout(self, curCble, layout, col);
0923:                Layout.Element[] res = new Layout.Element[col.size()];
0924:                col.toArray(res);
0925:                return res;
0926:            }
0927:
0928:            static//private
0929:            void tokenizeLayout(Layout self, int curCble, String layout,
0930:                    ArrayList col) {
0931:                boolean prevBCI = false;
0932:                for (int len = layout.length(), i = 0; i < len;) {
0933:                    int start = i;
0934:                    int body;
0935:                    Layout.Element e = self.new Element();
0936:                    byte kind;
0937:                    //System.out.println("at "+i+": ..."+layout.substring(i));
0938:                    // strip a prefix
0939:                    switch (layout.charAt(i++)) {
0940:                    /// layout_element: integral
0941:                    case 'B':
0942:                    case 'H':
0943:                    case 'I':
0944:                    case 'V': // unsigned_int
0945:                        kind = EK_INT;
0946:                        --i; // reparse
0947:                        i = tokenizeUInt(e, layout, i);
0948:                        break;
0949:                    case 'S': // signed_int
0950:                        kind = EK_INT;
0951:                        --i; // reparse
0952:                        i = tokenizeSInt(e, layout, i);
0953:                        break;
0954:                    case 'P': // bc_index
0955:                        kind = EK_BCI;
0956:                        if (layout.charAt(i++) == 'O') {
0957:                            // bc_index: 'PO' tokenizeUInt
0958:                            e.flags |= EF_DELTA;
0959:                            // must follow P or PO:
0960:                            if (!prevBCI) {
0961:                                i = -i;
0962:                                continue;
0963:                            } // fail
0964:                            i++; // move forward
0965:                        }
0966:                        --i; // reparse
0967:                        i = tokenizeUInt(e, layout, i);
0968:                        break;
0969:                    case 'O': // bc_offset
0970:                        kind = EK_BCO;
0971:                        e.flags |= EF_DELTA;
0972:                        // must follow P or PO:
0973:                        if (!prevBCI) {
0974:                            i = -i;
0975:                            continue;
0976:                        } // fail
0977:                        i = tokenizeSInt(e, layout, i);
0978:                        break;
0979:                    case 'F': // flag
0980:                        kind = EK_FLAG;
0981:                        i = tokenizeUInt(e, layout, i);
0982:                        break;
0983:                    case 'N': // replication: 'N' uint '[' elem ... ']'
0984:                        kind = EK_REPL;
0985:                        i = tokenizeUInt(e, layout, i);
0986:                        if (layout.charAt(i++) != '[') {
0987:                            i = -i;
0988:                            continue;
0989:                        } // fail
0990:                        i = skipBody(layout, body = i);
0991:                        e.body = tokenizeLayout(self, curCble, layout
0992:                                .substring(body, i++));
0993:                        break;
0994:                    case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']'
0995:                        kind = EK_UN;
0996:                        i = tokenizeSInt(e, layout, i);
0997:                        ArrayList cases = new ArrayList();
0998:                        for (;;) {
0999:                            // Keep parsing cases until we hit the default case.
1000:                            if (layout.charAt(i++) != '(') {
1001:                                i = -i;
1002:                                break;
1003:                            } // fail
1004:                            int beg = i;
1005:                            i = layout.indexOf(')', i);
1006:                            String cstr = layout.substring(beg, i++);
1007:                            int cstrlen = cstr.length();
1008:                            if (layout.charAt(i++) != '[') {
1009:                                i = -i;
1010:                                break;
1011:                            } // fail
1012:                            // Check for duplication.
1013:                            if (layout.charAt(i) == ']')
1014:                                body = i; // missing body, which is legal here
1015:                            else
1016:                                i = skipBody(layout, body = i);
1017:                            Layout.Element[] cbody = tokenizeLayout(self,
1018:                                    curCble, layout.substring(body, i++));
1019:                            if (cstrlen == 0) {
1020:                                Layout.Element ce = self.new Element();
1021:                                ce.body = cbody;
1022:                                ce.kind = EK_CASE;
1023:                                ce.removeBand();
1024:                                cases.add(ce);
1025:                                break; // done with the whole union
1026:                            } else {
1027:                                // Parse a case string.
1028:                                boolean firstCaseNum = true;
1029:                                for (int cp = 0, endp;; cp = endp + 1) {
1030:                                    // Look for multiple case tags:
1031:                                    endp = cstr.indexOf(',', cp);
1032:                                    if (endp < 0)
1033:                                        endp = cstrlen;
1034:                                    String cstr1 = cstr.substring(cp, endp);
1035:                                    if (cstr1.length() == 0)
1036:                                        cstr1 = "empty"; // will fail parse
1037:                                    int value0, value1;
1038:                                    // Check for a case range (new in 1.6).
1039:                                    int dash = findCaseDash(cstr1, 0);
1040:                                    if (dash >= 0) {
1041:                                        value0 = parseIntBefore(cstr1, dash);
1042:                                        value1 = parseIntAfter(cstr1, dash);
1043:                                        if (value0 >= value1) {
1044:                                            i = -i;
1045:                                            break;
1046:                                        } // fail
1047:                                    } else {
1048:                                        value0 = value1 = Integer
1049:                                                .parseInt(cstr1);
1050:                                    }
1051:                                    // Add a case for each value in value0..value1
1052:                                    for (;; value0++) {
1053:                                        Layout.Element ce = self.new Element();
1054:                                        ce.body = cbody; // all cases share one body
1055:                                        ce.kind = EK_CASE;
1056:                                        ce.removeBand();
1057:                                        if (!firstCaseNum)
1058:                                            // "backward case" repeats a body
1059:                                            ce.flags |= EF_BACK;
1060:                                        firstCaseNum = false;
1061:                                        ce.value = value0;
1062:                                        cases.add(ce);
1063:                                        if (value0 == value1)
1064:                                            break;
1065:                                    }
1066:                                    if (endp == cstrlen) {
1067:                                        break; // done with this case
1068:                                    }
1069:                                }
1070:                            }
1071:                        }
1072:                        e.body = new Layout.Element[cases.size()];
1073:                        cases.toArray(e.body);
1074:                        e.kind = kind;
1075:                        for (int j = 0; j < e.body.length - 1; j++) {
1076:                            Layout.Element ce = e.body[j];
1077:                            if (matchCase(e, ce.value) != ce) {
1078:                                // Duplicate tag.
1079:                                {
1080:                                    i = -i;
1081:                                    break;
1082:                                } // fail
1083:                            }
1084:                        }
1085:                        break;
1086:                    case '(': // call: '(' '-'? digit+ ')'
1087:                        kind = EK_CALL;
1088:                        e.removeBand();
1089:                        i = layout.indexOf(')', i);
1090:                        String cstr = layout.substring(start + 1, i++);
1091:                        int offset = Integer.parseInt(cstr);
1092:                        int target = curCble + offset;
1093:                        if (!(offset + "").equals(cstr) || self.elems == null
1094:                                || target < 0 || target >= self.elems.length) {
1095:                            i = -i;
1096:                            continue;
1097:                        } // fail
1098:                        Layout.Element ce = self.elems[target];
1099:                        assert (ce.kind == EK_CBLE);
1100:                        e.value = target;
1101:                        e.body = new Layout.Element[] { ce };
1102:                        // Is it a (recursive) backward call?
1103:                        if (offset <= 0) {
1104:                            // Yes.  Mark both caller and callee backward.
1105:                            e.flags |= EF_BACK;
1106:                            ce.flags |= EF_BACK;
1107:                        }
1108:                        break;
1109:                    case 'K': // reference_type: constant_ref
1110:                        kind = EK_REF;
1111:                        switch (layout.charAt(i++)) {
1112:                        case 'I':
1113:                            e.refKind = CONSTANT_Integer;
1114:                            break;
1115:                        case 'J':
1116:                            e.refKind = CONSTANT_Long;
1117:                            break;
1118:                        case 'F':
1119:                            e.refKind = CONSTANT_Float;
1120:                            break;
1121:                        case 'D':
1122:                            e.refKind = CONSTANT_Double;
1123:                            break;
1124:                        case 'S':
1125:                            e.refKind = CONSTANT_String;
1126:                            break;
1127:                        case 'Q':
1128:                            e.refKind = CONSTANT_Literal;
1129:                            break;
1130:                        default: {
1131:                            i = -i;
1132:                            continue;
1133:                        } // fail
1134:                        }
1135:                        break;
1136:                    case 'R': // schema_ref
1137:                        kind = EK_REF;
1138:                        switch (layout.charAt(i++)) {
1139:                        case 'C':
1140:                            e.refKind = CONSTANT_Class;
1141:                            break;
1142:                        case 'S':
1143:                            e.refKind = CONSTANT_Signature;
1144:                            break;
1145:                        case 'D':
1146:                            e.refKind = CONSTANT_NameandType;
1147:                            break;
1148:                        case 'F':
1149:                            e.refKind = CONSTANT_Fieldref;
1150:                            break;
1151:                        case 'M':
1152:                            e.refKind = CONSTANT_Methodref;
1153:                            break;
1154:                        case 'I':
1155:                            e.refKind = CONSTANT_InterfaceMethodref;
1156:                            break;
1157:
1158:                        case 'U':
1159:                            e.refKind = CONSTANT_Utf8;
1160:                            break; //utf8_ref
1161:                        case 'Q':
1162:                            e.refKind = CONSTANT_All;
1163:                            break; //untyped_ref
1164:
1165:                        default: {
1166:                            i = -i;
1167:                            continue;
1168:                        } // fail
1169:                        }
1170:                        break;
1171:                    default: {
1172:                        i = -i;
1173:                        continue;
1174:                    } // fail
1175:                    }
1176:
1177:                    // further parsing of refs
1178:                    if (kind == EK_REF) {
1179:                        // reference: reference_type -><- ( 'N' )? tokenizeUInt
1180:                        if (layout.charAt(i++) == 'N') {
1181:                            e.flags |= EF_NULL;
1182:                            i++; // move forward
1183:                        }
1184:                        --i; // reparse
1185:                        i = tokenizeUInt(e, layout, i);
1186:                        self.hasRefs = true;
1187:                    }
1188:
1189:                    prevBCI = (kind == EK_BCI);
1190:
1191:                    // store the new element
1192:                    e.kind = kind;
1193:                    e.layout = layout.substring(start, i);
1194:                    col.add(e);
1195:                }
1196:            }
1197:
1198:            static//private
1199:            String[] splitBodies(String layout) {
1200:                ArrayList bodies = new ArrayList();
1201:                // Parse several independent layout bodies:  "[foo][bar]...[baz]"
1202:                for (int i = 0; i < layout.length(); i++) {
1203:                    if (layout.charAt(i++) != '[')
1204:                        layout.charAt(-i); // throw error
1205:                    int body;
1206:                    i = skipBody(layout, body = i);
1207:                    bodies.add(layout.substring(body, i));
1208:                }
1209:                String[] res = new String[bodies.size()];
1210:                bodies.toArray(res);
1211:                return res;
1212:            }
1213:
1214:            static private int skipBody(String layout, int i) {
1215:                assert (layout.charAt(i - 1) == '[');
1216:                if (layout.charAt(i) == ']')
1217:                    // No empty bodies, please.
1218:                    return -i;
1219:                // skip balanced [...[...]...]
1220:                for (int depth = 1; depth > 0;) {
1221:                    switch (layout.charAt(i++)) {
1222:                    case '[':
1223:                        depth++;
1224:                        break;
1225:                    case ']':
1226:                        depth--;
1227:                        break;
1228:                    }
1229:                }
1230:                --i; // get before bracket
1231:                assert (layout.charAt(i) == ']');
1232:                return i; // return closing bracket
1233:            }
1234:
1235:            static private int tokenizeUInt(Layout.Element e, String layout,
1236:                    int i) {
1237:                switch (layout.charAt(i++)) {
1238:                case 'V':
1239:                    e.len = 0;
1240:                    break;
1241:                case 'B':
1242:                    e.len = 1;
1243:                    break;
1244:                case 'H':
1245:                    e.len = 2;
1246:                    break;
1247:                case 'I':
1248:                    e.len = 4;
1249:                    break;
1250:                default:
1251:                    return -i;
1252:                }
1253:                return i;
1254:            }
1255:
1256:            static private int tokenizeSInt(Layout.Element e, String layout,
1257:                    int i) {
1258:                if (layout.charAt(i) == 'S') {
1259:                    e.flags |= EF_SIGN;
1260:                    ++i;
1261:                }
1262:                return tokenizeUInt(e, layout, i);
1263:            }
1264:
1265:            static private boolean isDigit(char c) {
1266:                return c >= '0' && c <= '9';
1267:            }
1268:
1269:            /** Find an occurrence of hyphen '-' between two numerals. */
1270:            static//private
1271:            int findCaseDash(String layout, int fromIndex) {
1272:                if (fromIndex <= 0)
1273:                    fromIndex = 1; // minimum dash pos
1274:                int lastDash = layout.length() - 2; // maximum dash pos
1275:                for (;;) {
1276:                    int dash = layout.indexOf('-', fromIndex);
1277:                    if (dash < 0 || dash > lastDash)
1278:                        return -1;
1279:                    if (isDigit(layout.charAt(dash - 1))) {
1280:                        char afterDash = layout.charAt(dash + 1);
1281:                        if (afterDash == '-' && dash + 2 < layout.length())
1282:                            afterDash = layout.charAt(dash + 2);
1283:                        if (isDigit(afterDash)) {
1284:                            // matched /[0-9]--?[0-9]/; return position of dash
1285:                            return dash;
1286:                        }
1287:                    }
1288:                    fromIndex = dash + 1;
1289:                }
1290:            }
1291:
1292:            static int parseIntBefore(String layout, int dash) {
1293:                int end = dash;
1294:                int beg = end;
1295:                while (beg > 0 && isDigit(layout.charAt(beg - 1)))
1296:                    --beg;
1297:                if (beg == end)
1298:                    return Integer.parseInt("empty");
1299:                // skip backward over a sign
1300:                if (beg >= 1 && layout.charAt(beg - 1) == '-')
1301:                    --beg;
1302:                assert (beg == 0 || !isDigit(layout.charAt(beg - 1)));
1303:                return Integer.parseInt(layout.substring(beg, end));
1304:            }
1305:
1306:            static int parseIntAfter(String layout, int dash) {
1307:                int beg = dash + 1;
1308:                int end = beg;
1309:                int limit = layout.length();
1310:                if (end < limit && layout.charAt(end) == '-')
1311:                    ++end;
1312:                while (end < limit && isDigit(layout.charAt(end)))
1313:                    ++end;
1314:                if (beg == end)
1315:                    return Integer.parseInt("empty");
1316:                return Integer.parseInt(layout.substring(beg, end));
1317:            }
1318:
1319:            /** For compatibility with 1.5 pack, expand 1-5 into 1,2,3,4,5. */
1320:            static String expandCaseDashNotation(String layout) {
1321:                int dash = findCaseDash(layout, 0);
1322:                if (dash < 0)
1323:                    return layout; // no dashes (the common case)
1324:                StringBuffer result = new StringBuffer(layout.length() * 3);
1325:                int sofar = 0; // how far have we processed the layout?
1326:                for (;;) {
1327:                    // for each dash, collect everything up to the dash
1328:                    result.append(layout.substring(sofar, dash));
1329:                    sofar = dash + 1; // skip the dash
1330:                    // then collect intermediate values
1331:                    int value0 = parseIntBefore(layout, dash);
1332:                    int value1 = parseIntAfter(layout, dash);
1333:                    assert (value0 < value1);
1334:                    result.append(","); // close off value0 numeral
1335:                    for (int i = value0 + 1; i < value1; i++) {
1336:                        result.append(i);
1337:                        result.append(","); // close off i numeral
1338:                    }
1339:                    dash = findCaseDash(layout, sofar);
1340:                    if (dash < 0)
1341:                        break;
1342:                }
1343:                result.append(layout.substring(sofar)); // collect the rest
1344:                return result.toString();
1345:            }
1346:
1347:            static {
1348:                assert (expandCaseDashNotation("1-5").equals("1,2,3,4,5"));
1349:                assert (expandCaseDashNotation("-2--1").equals("-2,-1"));
1350:                assert (expandCaseDashNotation("-2-1").equals("-2,-1,0,1"));
1351:                assert (expandCaseDashNotation("-1-0").equals("-1,0"));
1352:            }
1353:
1354:            // Parse attribute bytes, putting values into bands.  Returns new pos.
1355:            // Used when reading a class file (local refs resolved with local cpMap).
1356:            // Also used for ad hoc scanning.
1357:            static int parseUsing(Layout.Element[] elems, Holder holder,
1358:                    byte[] bytes, int pos, int len, ValueStream out) {
1359:                int prevBCI = 0;
1360:                int prevRBCI = 0;
1361:                int end = pos + len;
1362:                int[] buf = { 0 }; // for calls to parseInt, holds 2nd result
1363:                for (int i = 0; i < elems.length; i++) {
1364:                    Layout.Element e = elems[i];
1365:                    int bandIndex = e.bandIndex;
1366:                    int value;
1367:                    int BCI, RBCI;
1368:                    switch (e.kind) {
1369:                    case EK_INT:
1370:                        pos = parseInt(e, bytes, pos, buf);
1371:                        value = buf[0];
1372:                        out.putInt(bandIndex, value);
1373:                        break;
1374:                    case EK_BCI: // PH, POH
1375:                        pos = parseInt(e, bytes, pos, buf);
1376:                        BCI = buf[0];
1377:                        RBCI = out.encodeBCI(BCI);
1378:                        if (!e.flagTest(EF_DELTA)) {
1379:                            // PH:  transmit R(bci), store bci
1380:                            value = RBCI;
1381:                        } else {
1382:                            // POH:  transmit D(R(bci)), store bci
1383:                            value = RBCI - prevRBCI;
1384:                        }
1385:                        prevBCI = BCI;
1386:                        prevRBCI = RBCI;
1387:                        out.putInt(bandIndex, value);
1388:                        break;
1389:                    case EK_BCO: // OH
1390:                        assert (e.flagTest(EF_DELTA));
1391:                        // OH:  transmit D(R(bci)), store D(bci)
1392:                        pos = parseInt(e, bytes, pos, buf);
1393:                        BCI = prevBCI + buf[0];
1394:                        RBCI = out.encodeBCI(BCI);
1395:                        value = RBCI - prevRBCI;
1396:                        prevBCI = BCI;
1397:                        prevRBCI = RBCI;
1398:                        out.putInt(bandIndex, value);
1399:                        break;
1400:                    case EK_FLAG:
1401:                        pos = parseInt(e, bytes, pos, buf);
1402:                        value = buf[0];
1403:                        out.putInt(bandIndex, value);
1404:                        break;
1405:                    case EK_REPL:
1406:                        pos = parseInt(e, bytes, pos, buf);
1407:                        value = buf[0];
1408:                        out.putInt(bandIndex, value);
1409:                        for (int j = 0; j < value; j++) {
1410:                            pos = parseUsing(e.body, holder, bytes, pos, end
1411:                                    - pos, out);
1412:                        }
1413:                        break; // already transmitted the scalar value
1414:                    case EK_UN:
1415:                        pos = parseInt(e, bytes, pos, buf);
1416:                        value = buf[0];
1417:                        out.putInt(bandIndex, value);
1418:                        Layout.Element ce = matchCase(e, value);
1419:                        pos = parseUsing(ce.body, holder, bytes, pos,
1420:                                end - pos, out);
1421:
1422:                        break; // already transmitted the scalar value
1423:                    case EK_CALL:
1424:                        // Adjust band offset if it is a backward call.
1425:                        assert (e.body.length == 1);
1426:                        assert (e.body[0].kind == EK_CBLE);
1427:                        if (e.flagTest(EF_BACK))
1428:                            out.noteBackCall(e.value);
1429:                        pos = parseUsing(e.body[0].body, holder, bytes, pos,
1430:                                end - pos, out);
1431:                        break; // no additional scalar value to transmit
1432:                    case EK_REF:
1433:                        pos = parseInt(e, bytes, pos, buf);
1434:                        int localRef = buf[0];
1435:                        Entry globalRef;
1436:                        if (localRef == 0) {
1437:                            globalRef = null; // N.B. global null reference is -1
1438:                        } else {
1439:                            globalRef = holder.getCPMap()[localRef];
1440:                            if (e.refKind == CONSTANT_Signature
1441:                                    && globalRef.getTag() == CONSTANT_Utf8) {
1442:                                // Cf. ClassReader.readSignatureRef.
1443:                                String typeName = globalRef.stringValue();
1444:                                globalRef = ConstantPool
1445:                                        .getSignatureEntry(typeName);
1446:                            } else if (e.refKind == CONSTANT_Literal) {
1447:                                assert (globalRef.getTag() >= CONSTANT_Integer);
1448:                                assert (globalRef.getTag() <= CONSTANT_String);
1449:                            } else if (e.refKind != CONSTANT_All) {
1450:                                assert (e.refKind == globalRef.getTag());
1451:                            }
1452:                        }
1453:                        out.putRef(bandIndex, globalRef);
1454:                        break;
1455:                    default:
1456:                        assert (false);
1457:                        continue;
1458:                    }
1459:                }
1460:                return pos;
1461:            }
1462:
1463:            static Layout.Element matchCase(Layout.Element e, int value) {
1464:                assert (e.kind == EK_UN);
1465:                int lastj = e.body.length - 1;
1466:                for (int j = 0; j < lastj; j++) {
1467:                    Layout.Element ce = e.body[j];
1468:                    assert (ce.kind == EK_CASE);
1469:                    if (value == ce.value)
1470:                        return ce;
1471:                }
1472:                return e.body[lastj];
1473:            }
1474:
1475:            static private int parseInt(Layout.Element e, byte[] bytes,
1476:                    int pos, int[] buf) {
1477:                int value = 0;
1478:                int loBits = e.len * 8;
1479:                // Read in big-endian order:
1480:                for (int bitPos = loBits; (bitPos -= 8) >= 0;) {
1481:                    value += (bytes[pos++] & 0xFF) << bitPos;
1482:                }
1483:                if (loBits < 32 && e.flagTest(EF_SIGN)) {
1484:                    // sign-extend subword value
1485:                    int hiBits = 32 - loBits;
1486:                    value = (value << hiBits) >> hiBits;
1487:                }
1488:                buf[0] = value;
1489:                return pos;
1490:            }
1491:
1492:            // Format attribute bytes, drawing values from bands.
1493:            // Used when emptying attribute bands into a package model.
1494:            // (At that point CP refs. are not yet assigned indexes.)
1495:            static void unparseUsing(Layout.Element[] elems, Object[] fixups,
1496:                    ValueStream in, ByteArrayOutputStream out) {
1497:                int prevBCI = 0;
1498:                int prevRBCI = 0;
1499:                for (int i = 0; i < elems.length; i++) {
1500:                    Layout.Element e = elems[i];
1501:                    int bandIndex = e.bandIndex;
1502:                    int value;
1503:                    int BCI, RBCI; // "RBCI" is R(BCI), BCI's coded representation
1504:                    switch (e.kind) {
1505:                    case EK_INT:
1506:                        value = in.getInt(bandIndex);
1507:                        unparseInt(e, value, out);
1508:                        break;
1509:                    case EK_BCI: // PH, POH
1510:                        value = in.getInt(bandIndex);
1511:                        if (!e.flagTest(EF_DELTA)) {
1512:                            // PH:  transmit R(bci), store bci
1513:                            RBCI = value;
1514:                        } else {
1515:                            // POH:  transmit D(R(bci)), store bci
1516:                            RBCI = prevRBCI + value;
1517:                        }
1518:                        assert (prevBCI == in.decodeBCI(prevRBCI));
1519:                        BCI = in.decodeBCI(RBCI);
1520:                        unparseInt(e, BCI, out);
1521:                        prevBCI = BCI;
1522:                        prevRBCI = RBCI;
1523:                        break;
1524:                    case EK_BCO: // OH
1525:                        value = in.getInt(bandIndex);
1526:                        assert (e.flagTest(EF_DELTA));
1527:                        // OH:  transmit D(R(bci)), store D(bci)
1528:                        assert (prevBCI == in.decodeBCI(prevRBCI));
1529:                        RBCI = prevRBCI + value;
1530:                        BCI = in.decodeBCI(RBCI);
1531:                        unparseInt(e, BCI - prevBCI, out);
1532:                        prevBCI = BCI;
1533:                        prevRBCI = RBCI;
1534:                        break;
1535:                    case EK_FLAG:
1536:                        value = in.getInt(bandIndex);
1537:                        unparseInt(e, value, out);
1538:                        break;
1539:                    case EK_REPL:
1540:                        value = in.getInt(bandIndex);
1541:                        unparseInt(e, value, out);
1542:                        for (int j = 0; j < value; j++) {
1543:                            unparseUsing(e.body, fixups, in, out);
1544:                        }
1545:                        break;
1546:                    case EK_UN:
1547:                        value = in.getInt(bandIndex);
1548:                        unparseInt(e, value, out);
1549:                        Layout.Element ce = matchCase(e, value);
1550:                        unparseUsing(ce.body, fixups, in, out);
1551:                        break;
1552:                    case EK_CALL:
1553:                        assert (e.body.length == 1);
1554:                        assert (e.body[0].kind == EK_CBLE);
1555:                        unparseUsing(e.body[0].body, fixups, in, out);
1556:                        break;
1557:                    case EK_REF:
1558:                        Entry globalRef = in.getRef(bandIndex);
1559:                        int localRef;
1560:                        if (globalRef != null) {
1561:                            // It's a one-element array, really an lvalue.
1562:                            fixups[0] = Fixups.add(fixups[0], null, out.size(),
1563:                                    Fixups.U2_FORMAT, globalRef);
1564:                            localRef = 0; // placeholder for fixups
1565:                        } else {
1566:                            localRef = 0; // fixed null value
1567:                        }
1568:                        unparseInt(e, localRef, out);
1569:                        break;
1570:                    default:
1571:                        assert (false);
1572:                        continue;
1573:                    }
1574:                }
1575:            }
1576:
1577:            static private void unparseInt(Layout.Element e, int value,
1578:                    ByteArrayOutputStream out) {
1579:                int loBits = e.len * 8;
1580:                if (loBits == 0) {
1581:                    // It is not stored at all ('V' layout).
1582:                    return;
1583:                }
1584:                if (loBits < 32) {
1585:                    int hiBits = 32 - loBits;
1586:                    int codedValue;
1587:                    if (e.flagTest(EF_SIGN))
1588:                        codedValue = (value << hiBits) >> hiBits;
1589:                    else
1590:                        codedValue = (value << hiBits) >>> hiBits;
1591:                    if (codedValue != value)
1592:                        throw new InternalError("cannot code in " + e.len
1593:                                + " bytes: " + value);
1594:                }
1595:                // Write in big-endian order:
1596:                for (int bitPos = loBits; (bitPos -= 8) >= 0;) {
1597:                    out.write((byte) (value >>> bitPos));
1598:                }
1599:            }
1600:
1601:            /*
1602:             /// Testing.
1603:             public static void main(String av[]) {
1604:             int maxVal = 12;
1605:             int iters = 0;
1606:             boolean verbose;
1607:             int ap = 0;
1608:             while (ap < av.length) {
1609:             if (!av[ap].startsWith("-"))  break;
1610:             if (av[ap].startsWith("-m"))
1611:             maxVal = Integer.parseInt(av[ap].substring(2));
1612:             else if (av[ap].startsWith("-i"))
1613:             iters = Integer.parseInt(av[ap].substring(2));
1614:             else
1615:             throw new RuntimeException("Bad option: "+av[ap]);
1616:             ap++;
1617:             }
1618:             verbose = (iters == 0);
1619:             if (iters <= 0)  iters = 1;
1620:             if (ap == av.length) {
1621:             av = new String[] {
1622:             "HH",	      // ClassFile.version
1623:             "RUH",	      // SourceFile
1624:             "RCHRDNH",    // EnclosingMethod
1625:             "KQH",	      // ConstantValue
1626:             "NH[RCH]",    // Exceptions
1627:             "NH[PHH]",    // LineNumberTable
1628:             "NH[PHOHRUHRSHH]",	// LocalVariableTable
1629:             "NH[PHPOHIIH]",		// CharacterRangeTable
1630:             "NH[PHHII]",		// CoverageTable
1631:             "NH[RCHRCNHRUNHFH]",	// InnerClasses
1632:             "HHNI[B]NH[PHPOHPOHRCNH]NH[RUHNI[B]]", // Code
1633:             "=AnnotationDefault",
1634:             // Like metadata, but with a compact tag set:
1635:             "[NH[(1)]]"
1636:             +"[NH[(2)]]"
1637:             +"[RSHNH[RUH(3)]]"
1638:             +"[TB(0,1,3)[KIH](2)[KDH](5)[KFH](4)[KJH](7)[RSH](8)[RSHRUH](9)[RUH](10)[(2)](6)[NH[(3)]]()[]]",
1639:             ""
1640:             };
1641:             ap = 0;
1642:             }
1643:             final int[][] counts = new int[2][3];  // int bci ref
1644:             final Entry[] cpMap = new Entry[maxVal+1];
1645:             for (int i = 0; i < cpMap.length; i++) {
1646:             if (i == 0)  continue;  // 0 => null
1647:             cpMap[i] = ConstantPool.getLiteralEntry(new Integer(i));
1648:             }
1649:             Class cls = new Package().new Class("");
1650:             cls.cpMap = cpMap;
1651:             class TestValueStream extends ValueStream {
1652:             Random rand = new Random(0);
1653:             ArrayList history = new ArrayList();
1654:             int ckidx = 0;
1655:             int maxVal;
1656:             boolean verbose;
1657:             void reset() { history.clear(); ckidx = 0; }
1658:             public int getInt(int bandIndex) {
1659:             counts[0][0]++;
1660:             int value = rand.nextInt(maxVal+1);
1661:             history.add(new Integer(bandIndex));
1662:             history.add(new Integer(value));
1663:             return value;
1664:             }
1665:             public void putInt(int bandIndex, int token) {
1666:             counts[1][0]++;
1667:             if (verbose)
1668:             System.out.print(" "+bandIndex+":"+token);
1669:             // Make sure this put parallels a previous get:
1670:             int check0 = ((Integer)history.get(ckidx+0)).intValue();
1671:             int check1 = ((Integer)history.get(ckidx+1)).intValue();
1672:             if (check0 != bandIndex || check1 != token) {
1673:             if (!verbose)
1674:             System.out.println(history.subList(0, ckidx));
1675:             System.out.println(" *** Should be "+check0+":"+check1);
1676:             throw new RuntimeException("Failed test!");
1677:             }
1678:             ckidx += 2;
1679:             }
1680:             public Entry getRef(int bandIndex) {
1681:             counts[0][2]++;
1682:             int value = getInt(bandIndex);
1683:             if (value < 0 || value > maxVal) {
1684:             System.out.println(" *** Unexpected ref code "+value);
1685:             return ConstantPool.getLiteralEntry(new Integer(value));
1686:             }
1687:             return cpMap[value];
1688:             }
1689:             public void putRef(int bandIndex, Entry ref) {
1690:             counts[1][2]++;
1691:             if (ref == null) {
1692:             putInt(bandIndex, 0);
1693:             return;
1694:             }
1695:             Number refValue = null;
1696:             if (ref instanceof ConstantPool.NumberEntry)
1697:             refValue = ((ConstantPool.NumberEntry)ref).numberValue();
1698:             int value;
1699:             if (!(refValue instanceof Integer)) {
1700:             System.out.println(" *** Unexpected ref "+ref);
1701:             value = -1;
1702:             } else {
1703:             value = ((Integer)refValue).intValue();
1704:             }
1705:             putInt(bandIndex, value);
1706:             }
1707:             public int encodeBCI(int bci) {
1708:             counts[1][1]++;
1709:             // move LSB to MSB of low byte
1710:             int code = (bci >> 8) << 8;  // keep high bits
1711:             code += (bci & 0xFE) >> 1;
1712:             code += (bci & 0x01) << 7;
1713:             return code ^ (8<<8);  // mark it clearly as coded
1714:             }
1715:             public int decodeBCI(int bciCode) {
1716:             counts[0][1]++;
1717:             bciCode ^= (8<<8);  // remove extra mark
1718:             int bci = (bciCode >> 8) << 8;  // keep high bits
1719:             bci += (bciCode & 0x7F) << 1;
1720:             bci += (bciCode & 0x80) >> 7;
1721:             return bci;
1722:             }
1723:             }
1724:             TestValueStream tts = new TestValueStream();
1725:             tts.maxVal = maxVal;
1726:             tts.verbose = verbose;
1727:             ByteArrayOutputStream buf = new ByteArrayOutputStream();
1728:             for (int i = 0; i < (1 << 30); i = (i + 1) * 5) {
1729:             int ei = tts.encodeBCI(i);
1730:             int di = tts.decodeBCI(ei);
1731:             if (di != i)  System.out.println("i="+Integer.toHexString(i)+
1732:             " ei="+Integer.toHexString(ei)+
1733:             " di="+Integer.toHexString(di));
1734:             }
1735:             while (iters-- > 0) {
1736:             for (int i = ap; i < av.length; i++) {
1737:             String layout = av[i];
1738:             if (layout.startsWith("=")) {
1739:             String name = layout.substring(1);
1740:             for (Iterator j = standardDefs.values().iterator(); j.hasNext(); ) {
1741:             Attribute a = (Attribute) j.next();
1742:             if (a.name().equals(name)) {
1743:             layout = a.layout().layout();
1744:             break;
1745:             }
1746:             }
1747:             if (layout.startsWith("=")) {
1748:             System.out.println("Could not find "+name+" in "+standardDefs.values());
1749:             }
1750:             }
1751:             Layout self = new Layout(0, "Foo", layout);
1752:             if (verbose) {
1753:             System.out.print("/"+layout+"/ => ");
1754:             System.out.println(Arrays.asList(self.elems));
1755:             }
1756:             buf.reset();
1757:             tts.reset();
1758:             Object fixups = self.unparse(tts, buf);
1759:             byte[] bytes = buf.toByteArray();
1760:             // Attach the references to the byte array.
1761:             Fixups.setBytes(fixups, bytes);
1762:             // Patch the references to their frozen values.
1763:             Fixups.finishRefs(fixups, bytes, new Index("test", cpMap));
1764:             if (verbose) {
1765:             System.out.print("  bytes: {");
1766:             for (int j = 0; j < bytes.length; j++) {
1767:             System.out.print(" "+bytes[j]);
1768:             }
1769:             System.out.println("}");
1770:             }
1771:             if (verbose) {
1772:             System.out.print("  parse: {");
1773:             }
1774:             self.parse(0, cls, bytes, 0, bytes.length, tts);
1775:             if (verbose) {
1776:             System.out.println("}");
1777:             }
1778:             }
1779:             }
1780:             for (int j = 0; j <= 1; j++) {
1781:             System.out.print("values "+(j==0?"read":"written")+": {");
1782:             for (int k = 0; k < counts[j].length; k++) {
1783:             System.out.print(" "+counts[j][k]);
1784:             }
1785:             System.out.println(" }");
1786:             }
1787:             }
1788:             //*/
1789:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.