src/share/classes/com/sun/tools/javah/LLNI.java

Thu, 10 Jun 2010 16:08:01 -0700

author
jjg
date
Thu, 10 Jun 2010 16:08:01 -0700
changeset 581
f2fdd52e4e87
parent 575
9a7c998bf2fc
child 712
a1d31ab7b525
permissions
-rw-r--r--

6944312: Potential rebranding issues in openjdk/langtools repository sources
Reviewed-by: darcy

     1 /*
     2  * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    27 package com.sun.tools.javah;
    29 import java.io.OutputStream;
    30 import java.io.PrintWriter;
    31 import java.util.ArrayList;
    32 import java.util.HashSet;
    33 import java.util.List;
    35 import java.util.Set;
    36 import javax.lang.model.element.Element;
    37 import javax.lang.model.element.ExecutableElement;
    38 import javax.lang.model.element.Modifier;
    39 import javax.lang.model.element.Name;
    40 import javax.lang.model.element.TypeElement;
    41 import javax.lang.model.element.VariableElement;
    42 import javax.lang.model.type.ArrayType;
    43 import javax.lang.model.type.PrimitiveType;
    44 import javax.lang.model.type.TypeKind;
    45 import javax.lang.model.type.TypeMirror;
    46 import javax.lang.model.type.TypeVisitor;
    47 import javax.lang.model.util.ElementFilter;
    48 import javax.lang.model.util.SimpleTypeVisitor7;
    50 /*
    51  * <p><b>This is NOT part of any supported API.
    52  * If you write code that depends on this, you do so at your own
    53  * risk.  This code and its internal interfaces are subject to change
    54  * or deletion without notice.</b></p>
    55  *
    56  * @author  Sucheta Dambalkar(Revised)
    57  */
    58 public class LLNI extends Gen {
    60     protected final char  innerDelim = '$';     /* For inner classes */
    61     protected Set<String>  doneHandleTypes;
    62     List<VariableElement> fields;
    63     List<ExecutableElement> methods;
    64     private boolean       doubleAlign;
    65     private int           padFieldNum = 0;
    67     LLNI(boolean doubleAlign, Util util) {
    68         super(util);
    69         this.doubleAlign = doubleAlign;
    70     }
    72     protected String getIncludes() {
    73         return "";
    74     }
    76     protected void write(OutputStream o, TypeElement clazz) throws Util.Exit {
    77         String cname     = mangleClassName(clazz.getQualifiedName().toString());
    78         PrintWriter pw   = wrapWriter(o);
    79         fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
    80         methods = ElementFilter.methodsIn(clazz.getEnclosedElements());
    81         generateDeclsForClass(pw, clazz, cname);
    82         // FIXME check if errors occurred on the PrintWriter and throw exception if so
    83     }
    85     protected void generateDeclsForClass(PrintWriter pw,
    86             TypeElement clazz, String cname) throws Util.Exit {
    87         doneHandleTypes  = new HashSet<String>();
    88         /* The following handle types are predefined in "typedefs.h". Suppress
    89            inclusion in the output by generating them "into the blue" here. */
    90         genHandleType(null, "java.lang.Class");
    91         genHandleType(null, "java.lang.ClassLoader");
    92         genHandleType(null, "java.lang.Object");
    93         genHandleType(null, "java.lang.String");
    94         genHandleType(null, "java.lang.Thread");
    95         genHandleType(null, "java.lang.ThreadGroup");
    96         genHandleType(null, "java.lang.Throwable");
    98         pw.println("/* LLNI Header for class " + clazz.getQualifiedName() + " */" + lineSep);
    99         pw.println("#ifndef _Included_" + cname);
   100         pw.println("#define _Included_" + cname);
   101         pw.println("#include \"typedefs.h\"");
   102         pw.println("#include \"llni.h\"");
   103         pw.println("#include \"jni.h\"" + lineSep);
   105         forwardDecls(pw, clazz);
   106         structSectionForClass(pw, clazz, cname);
   107         methodSectionForClass(pw, clazz, cname);
   108         pw.println("#endif");
   109     }
   111     protected void genHandleType(PrintWriter pw, String clazzname) {
   112         String cname = mangleClassName(clazzname);
   113         if (!doneHandleTypes.contains(cname)) {
   114             doneHandleTypes.add(cname);
   115             if (pw != null) {
   116                 pw.println("#ifndef DEFINED_" + cname);
   117                 pw.println("    #define DEFINED_" + cname);
   118                 pw.println("    GEN_HANDLE_TYPES(" + cname + ");");
   119                 pw.println("#endif" + lineSep);
   120             }
   121         }
   122     }
   124     protected String mangleClassName(String s) {
   125         return s.replace('.', '_')
   126             .replace('/', '_')
   127             .replace(innerDelim, '_');
   128     }
   130     protected void forwardDecls(PrintWriter pw, TypeElement clazz) {
   131         TypeElement object = elems.getTypeElement("java.lang.Object");
   132         if (clazz.equals(object))
   133             return;
   135         genHandleType(pw, clazz.getQualifiedName().toString());
   136         TypeElement superClass = (TypeElement) (types.asElement(clazz.getSuperclass()));
   138         if (superClass != null) {
   139             String superClassName = superClass.getQualifiedName().toString();
   140             forwardDecls(pw, superClass);
   141         }
   143         for (VariableElement field: fields) {
   145             if (!field.getModifiers().contains(Modifier.STATIC)) {
   146                 TypeMirror t = types.erasure(field.asType());
   147                 TypeSignature newTypeSig = new TypeSignature(elems);
   148                 String tname = newTypeSig.qualifiedTypeName(t);
   149                 String sig = newTypeSig.getTypeSignature(tname);
   151                 if (sig.charAt(0) != '[')
   152                     forwardDeclsFromSig(pw, sig);
   153             }
   154         }
   156         for (ExecutableElement method: methods) {
   158             if (method.getModifiers().contains(Modifier.NATIVE)) {
   159                 TypeMirror retType = types.erasure(method.getReturnType());
   160                 String typesig = signature(method);
   161                 TypeSignature newTypeSig = new TypeSignature(elems);
   162                 String sig = newTypeSig.getTypeSignature(typesig, retType);
   164                 if (sig.charAt(0) != '[')
   165                     forwardDeclsFromSig(pw, sig);
   167             }
   168         }
   169     }
   171     protected void forwardDeclsFromSig(PrintWriter pw, String sig) {
   172         int    len = sig.length();
   173         int    i   = sig.charAt(0) == '(' ? 1 : 0;
   175         /* Skip the initial "(". */
   176         while (i < len) {
   177             if (sig.charAt(i) == 'L') {
   178                 int j = i + 1;
   179                 while (sig.charAt(j) != ';') j++;
   180                 genHandleType(pw, sig.substring(i + 1, j));
   181                 i = j + 1;
   182             } else {
   183                 i++;
   184             }
   185         }
   186     }
   188     protected void structSectionForClass(PrintWriter pw,
   189                                          TypeElement jclazz, String cname) {
   191         String jname = jclazz.getQualifiedName().toString();
   193         if (cname.equals("java_lang_Object")) {
   194             pw.println("/* struct java_lang_Object is defined in typedefs.h. */");
   195             pw.println();
   196             return;
   197         }
   198         pw.println("#if !defined(__i386)");
   199         pw.println("#pragma pack(4)");
   200         pw.println("#endif");
   201         pw.println();
   202         pw.println("struct " + cname + " {");
   203         pw.println("    ObjHeader h;");
   204         pw.print(fieldDefs(jclazz, cname));
   206         if (jname.equals("java.lang.Class"))
   207             pw.println("    Class *LLNI_mask(cClass);" +
   208                        "  /* Fake field; don't access (see oobj.h) */");
   209         pw.println("};" + lineSep + lineSep + "#pragma pack()");
   210         pw.println();
   211         return;
   212     }
   214     private static class FieldDefsRes {
   215         public String className;        /* Name of the current class. */
   216         public FieldDefsRes parent;
   217         public String s;
   218         public int byteSize;
   219         public boolean bottomMost;
   220         public boolean printedOne = false;
   222         FieldDefsRes(TypeElement clazz, FieldDefsRes parent, boolean bottomMost) {
   223             this.className = clazz.getQualifiedName().toString();
   224             this.parent = parent;
   225             this.bottomMost = bottomMost;
   226             int byteSize = 0;
   227             if (parent == null) this.s = "";
   228             else this.s = parent.s;
   229         }
   230     }
   232     /* Returns "true" iff added a field. */
   233     private boolean doField(FieldDefsRes res, VariableElement field,
   234                             String cname, boolean padWord) {
   236         String fieldDef = addStructMember(field, cname, padWord);
   237         if (fieldDef != null) {
   238             if (!res.printedOne) { /* add separator */
   239                 if (res.bottomMost) {
   240                     if (res.s.length() != 0)
   241                         res.s = res.s + "    /* local members: */" + lineSep;
   242                 } else {
   243                     res.s = res.s + "    /* inherited members from " +
   244                         res.className + ": */" + lineSep;
   245                 }
   246                 res.printedOne = true;
   247             }
   248             res.s = res.s + fieldDef;
   249             return true;
   250         }
   252         // Otherwise.
   253         return false;
   254     }
   256     private int doTwoWordFields(FieldDefsRes res, TypeElement clazz,
   257                                 int offset, String cname, boolean padWord) {
   258         boolean first = true;
   259         List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
   261         for (VariableElement field: fields) {
   262             TypeKind tk = field.asType().getKind();
   263             boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
   264             if (twoWords && doField(res, field, cname, first && padWord)) {
   265                 offset += 8; first = false;
   266             }
   267         }
   268         return offset;
   269     }
   271     String fieldDefs(TypeElement clazz, String cname) {
   272         FieldDefsRes res = fieldDefs(clazz, cname, true);
   273         return res.s;
   274     }
   276     FieldDefsRes fieldDefs(TypeElement clazz, String cname,
   277                                      boolean bottomMost){
   278         FieldDefsRes res;
   279         int offset;
   280         boolean didTwoWordFields = false;
   282         TypeElement superclazz = (TypeElement) types.asElement(clazz.getSuperclass());
   284         if (superclazz != null) {
   285             String supername = superclazz.getQualifiedName().toString();
   286             res = new FieldDefsRes(clazz,
   287                                    fieldDefs(superclazz, cname, false),
   288                                    bottomMost);
   289             offset = res.parent.byteSize;
   290         } else {
   291             res = new FieldDefsRes(clazz, null, bottomMost);
   292             offset = 0;
   293         }
   295         List<VariableElement> fields = ElementFilter.fieldsIn(clazz.getEnclosedElements());
   297         for (VariableElement field: fields) {
   299             if (doubleAlign && !didTwoWordFields && (offset % 8) == 0) {
   300                 offset = doTwoWordFields(res, clazz, offset, cname, false);
   301                 didTwoWordFields = true;
   302             }
   304             TypeKind tk = field.asType().getKind();
   305             boolean twoWords = (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
   307             if (!doubleAlign || !twoWords) {
   308                 if (doField(res, field, cname, false)) offset += 4;
   309             }
   311         }
   313         if (doubleAlign && !didTwoWordFields) {
   314             if ((offset % 8) != 0) offset += 4;
   315             offset = doTwoWordFields(res, clazz, offset, cname, true);
   316         }
   318         res.byteSize = offset;
   319         return res;
   320     }
   322     /* OVERRIDE: This method handles instance fields */
   323     protected String addStructMember(VariableElement member, String cname,
   324                                      boolean padWord) {
   325         String res = null;
   327         if (member.getModifiers().contains(Modifier.STATIC)) {
   328             res = addStaticStructMember(member, cname);
   329             //   if (res == null) /* JNI didn't handle it, print comment. */
   330             //  res = "    /* Inaccessible static: " + member + " */" + lineSep;
   331         } else {
   332             TypeMirror mt = types.erasure(member.asType());
   333             if (padWord) res = "    java_int padWord" + padFieldNum++ + ";" + lineSep;
   334             res = "    " + llniType(mt, false, false) + " " + llniFieldName(member);
   335             if (isLongOrDouble(mt)) res = res + "[2]";
   336             res = res + ";" + lineSep;
   337         }
   338         return res;
   339     }
   341     static private final boolean isWindows =
   342         System.getProperty("os.name").startsWith("Windows");
   344     /*
   345      * This method only handles static final fields.
   346      */
   347     protected String addStaticStructMember(VariableElement field, String cname) {
   348         String res = null;
   349         Object exp = null;
   351         if (!field.getModifiers().contains(Modifier.STATIC))
   352             return res;
   353         if (!field.getModifiers().contains(Modifier.FINAL))
   354             return res;
   356         exp = field.getConstantValue();
   358         if (exp != null) {
   359             /* Constant. */
   361             String     cn     = cname + "_" + field.getSimpleName();
   362             String     suffix = null;
   363             long           val = 0;
   364             /* Can only handle int, long, float, and double fields. */
   365             if (exp instanceof Byte
   366                 || exp instanceof Short
   367                 || exp instanceof Integer) {
   368                 suffix = "L";
   369                 val = ((Number)exp).intValue();
   370             }
   371             else if (exp instanceof Long) {
   372                 // Visual C++ supports the i64 suffix, not LL
   373                 suffix = isWindows ? "i64" : "LL";
   374                 val = ((Long)exp).longValue();
   375             }
   376             else if (exp instanceof Float)  suffix = "f";
   377             else if (exp instanceof Double) suffix = "";
   378             else if (exp instanceof Character) {
   379                 suffix = "L";
   380                 Character ch = (Character) exp;
   381                 val = ((int) ch) & 0xffff;
   382             }
   383             if (suffix != null) {
   384                 // Some compilers will generate a spurious warning
   385                 // for the integer constants for Integer.MIN_VALUE
   386                 // and Long.MIN_VALUE so we handle them specially.
   387                 if ((suffix.equals("L") && (val == Integer.MIN_VALUE)) ||
   388                     (suffix.equals("LL") && (val == Long.MIN_VALUE))) {
   389                     res = "    #undef  " + cn + lineSep
   390                         + "    #define " + cn
   391                         + " (" + (val + 1) + suffix + "-1)" + lineSep;
   392                 } else if (suffix.equals("L") || suffix.endsWith("LL")) {
   393                     res = "    #undef  " + cn + lineSep
   394                         + "    #define " + cn + " " + val + suffix + lineSep;
   395                 } else {
   396                     res = "    #undef  " + cn + lineSep
   397                         + "    #define " + cn + " " + exp + suffix + lineSep;
   398                 }
   399             }
   400         }
   401         return res;
   402     }
   404     protected void methodSectionForClass(PrintWriter pw,
   405             TypeElement clazz, String cname)
   406             throws Util.Exit {
   407         String methods = methodDecls(clazz, cname);
   409         if (methods.length() != 0) {
   410             pw.println("/* Native method declarations: */" + lineSep);
   411             pw.println("#ifdef __cplusplus");
   412             pw.println("extern \"C\" {");
   413             pw.println("#endif" + lineSep);
   414             pw.println(methods);
   415             pw.println("#ifdef __cplusplus");
   416             pw.println("}");
   417             pw.println("#endif");
   418         }
   419     }
   421     protected String methodDecls(TypeElement clazz, String cname) throws Util.Exit {
   423         String res = "";
   424         for (ExecutableElement method: methods) {
   425             if (method.getModifiers().contains(Modifier.NATIVE))
   426                 res = res + methodDecl(method, clazz, cname);
   427         }
   428         return res;
   429     }
   431     protected String methodDecl(ExecutableElement method,
   432                                 TypeElement clazz, String cname)
   433     throws Util.Exit {
   434         String res = null;
   436         TypeMirror retType = types.erasure(method.getReturnType());
   437         String typesig = signature(method);
   438         TypeSignature newTypeSig = new TypeSignature(elems);
   439         String sig = newTypeSig.getTypeSignature(typesig, retType);
   440         boolean longName = needLongName(method, clazz);
   442         if (sig.charAt(0) != '(')
   443             util.error("invalid.method.signature", sig);
   446         res = "JNIEXPORT " + jniType(retType) + " JNICALL" + lineSep + jniMethodName(method, cname, longName)
   447             + "(JNIEnv *, " + cRcvrDecl(method, cname);
   448         List<? extends VariableElement> params = method.getParameters();
   449         List<TypeMirror> argTypes = new ArrayList<TypeMirror>();
   450         for (VariableElement p: params){
   451             argTypes.add(types.erasure(p.asType()));
   452         }
   454         /* It would have been nice to include the argument names in the
   455            declaration, but there seems to be a bug in the "BinaryField"
   456            class, causing the getArguments() method to return "null" for
   457            most (non-constructor) methods. */
   458         for (TypeMirror argType: argTypes)
   459             res = res + ", " + jniType(argType);
   460         res = res + ");" + lineSep;
   461         return res;
   462     }
   464     protected final boolean needLongName(ExecutableElement method,
   465                                          TypeElement clazz) {
   466         Name methodName = method.getSimpleName();
   467         for (ExecutableElement memberMethod: methods) {
   468             if ((memberMethod != method) &&
   469                 memberMethod.getModifiers().contains(Modifier.NATIVE) &&
   470                     (methodName.equals(memberMethod.getSimpleName())))
   471                 return true;
   472         }
   473         return false;
   474     }
   476     protected final String jniMethodName(ExecutableElement method, String cname,
   477                                          boolean longName) {
   478         String res = "Java_" + cname + "_" + method.getSimpleName();
   480         if (longName) {
   481             TypeMirror mType =  types.erasure(method.getReturnType());
   482             List<? extends VariableElement> params = method.getParameters();
   483             List<TypeMirror> argTypes = new ArrayList<TypeMirror>();
   484             for (VariableElement param: params) {
   485                 argTypes.add(types.erasure(param.asType()));
   486             }
   488             res = res + "__";
   489             for (TypeMirror t: argTypes) {
   490                 String tname = t.toString();
   491                 TypeSignature newTypeSig = new TypeSignature(elems);
   492                 String sig = newTypeSig.getTypeSignature(tname);
   493                 res = res + nameToIdentifier(sig);
   494             }
   495         }
   496         return res;
   497     }
   499     // copied from JNI.java
   500     protected final String jniType(TypeMirror t) throws Util.Exit {
   501         TypeElement throwable = elems.getTypeElement("java.lang.Throwable");
   502         TypeElement jClass = elems.getTypeElement("java.lang.Class");
   503         TypeElement jString = elems.getTypeElement("java.lang.String");
   504         Element tclassDoc = types.asElement(t);
   506         switch (t.getKind()) {
   507             case ARRAY: {
   508                 TypeMirror ct = ((ArrayType) t).getComponentType();
   509                 switch (ct.getKind()) {
   510                     case BOOLEAN:  return "jbooleanArray";
   511                     case BYTE:     return "jbyteArray";
   512                     case CHAR:     return "jcharArray";
   513                     case SHORT:    return "jshortArray";
   514                     case INT:      return "jintArray";
   515                     case LONG:     return "jlongArray";
   516                     case FLOAT:    return "jfloatArray";
   517                     case DOUBLE:   return "jdoubleArray";
   518                     case ARRAY:
   519                     case DECLARED: return "jobjectArray";
   520                     default: throw new Error(ct.toString());
   521                 }
   522             }
   524             case VOID:     return "void";
   525             case BOOLEAN:  return "jboolean";
   526             case BYTE:     return "jbyte";
   527             case CHAR:     return "jchar";
   528             case SHORT:    return "jshort";
   529             case INT:      return "jint";
   530             case LONG:     return "jlong";
   531             case FLOAT:    return "jfloat";
   532             case DOUBLE:   return "jdouble";
   534             case DECLARED: {
   535                 if (tclassDoc.equals(jString))
   536                     return "jstring";
   537                 else if (types.isAssignable(t, throwable.asType()))
   538                     return "jthrowable";
   539                 else if (types.isAssignable(t, jClass.asType()))
   540                     return "jclass";
   541                 else
   542                     return "jobject";
   543             }
   544         }
   546         util.bug("jni.unknown.type");
   547         return null; /* dead code. */
   548     }
   550     protected String llniType(TypeMirror t, boolean handleize, boolean longDoubleOK) {
   551         String res = null;
   553         switch (t.getKind()) {
   554             case ARRAY: {
   555                 TypeMirror ct = ((ArrayType) t).getComponentType();
   556                 switch (ct.getKind()) {
   557                     case BOOLEAN:  res = "IArrayOfBoolean"; break;
   558                     case BYTE:     res = "IArrayOfByte";    break;
   559                     case CHAR:     res = "IArrayOfChar";    break;
   560                     case SHORT:    res = "IArrayOfShort";   break;
   561                     case INT:      res = "IArrayOfInt";     break;
   562                     case LONG:     res = "IArrayOfLong";    break;
   563                     case FLOAT:    res = "IArrayOfFloat";   break;
   564                     case DOUBLE:   res = "IArrayOfDouble";  break;
   565                     case ARRAY:
   566                     case DECLARED: res = "IArrayOfRef";     break;
   567                     default: throw new Error(ct.getKind() + " " + ct);
   568                 }
   569                 if (!handleize) res = "DEREFERENCED_" + res;
   570                 break;
   571             }
   573             case VOID:
   574                 res = "void";
   575                 break;
   577             case BOOLEAN:
   578             case BYTE:
   579             case CHAR:
   580             case SHORT:
   581             case INT:
   582                 res = "java_int" ;
   583                 break;
   585             case LONG:
   586                 res = longDoubleOK ? "java_long" : "val32 /* java_long */";
   587                 break;
   589             case FLOAT:
   590                 res =  "java_float";
   591                 break;
   593             case DOUBLE:
   594                 res = longDoubleOK ? "java_double" : "val32 /* java_double */";
   595                 break;
   597             case DECLARED:
   598                 TypeElement e  = (TypeElement) types.asElement(t);
   599                 res = "I" +  mangleClassName(e.getQualifiedName().toString());
   600                 if (!handleize) res = "DEREFERENCED_" + res;
   601                 break;
   603             default:
   604                 throw new Error(t.getKind() + " " + t); // FIXME
   605         }
   607         return res;
   608     }
   610     protected final String cRcvrDecl(Element field, String cname) {
   611         return (field.getModifiers().contains(Modifier.STATIC) ? "jclass" : "jobject");
   612     }
   614     protected String maskName(String s) {
   615         return "LLNI_mask(" + s + ")";
   616     }
   618     protected String llniFieldName(VariableElement field) {
   619         return maskName(field.getSimpleName().toString());
   620     }
   622     protected final boolean isLongOrDouble(TypeMirror t) {
   623         TypeVisitor<Boolean,Void> v = new SimpleTypeVisitor7<Boolean,Void>() {
   624             public Boolean defaultAction(TypeMirror t, Void p){
   625                 return false;
   626             }
   627             public Boolean visitArray(ArrayType t, Void p) {
   628                 return visit(t.getComponentType(), p);
   629             }
   630             public Boolean visitPrimitive(PrimitiveType t, Void p) {
   631                 TypeKind tk = t.getKind();
   632                 return (tk == TypeKind.LONG || tk == TypeKind.DOUBLE);
   633             }
   634         };
   635         return v.visit(t, null);
   636     }
   638     /* Do unicode to ansi C identifier conversion.
   639        %%% This may not be right, but should be called more often. */
   640     protected final String nameToIdentifier(String name) {
   641         int len = name.length();
   642         StringBuffer buf = new StringBuffer(len);
   643         for (int i = 0; i < len; i++) {
   644             char c = name.charAt(i);
   645             if (isASCIILetterOrDigit(c))
   646                 buf.append(c);
   647             else if (c == '/')
   648                 buf.append('_');
   649             else if (c == '.')
   650                 buf.append('_');
   651             else if (c == '_')
   652                 buf.append("_1");
   653             else if (c == ';')
   654                 buf.append("_2");
   655             else if (c == '[')
   656                 buf.append("_3");
   657             else
   658                 buf.append("_0" + ((int)c));
   659         }
   660         return new String(buf);
   661     }
   663     protected final boolean isASCIILetterOrDigit(char c) {
   664         if (((c >= 'A') && (c <= 'Z')) ||
   665             ((c >= 'a') && (c <= 'z')) ||
   666             ((c >= '0') && (c <= '9')))
   667             return true;
   668         else
   669             return false;
   670     }
   671 }

mercurial