src/share/jaxws_classes/com/sun/xml/internal/bind/DatatypeConverterImpl.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 514
29a761eaff0d
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2014, 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  */
    26 package com.sun.xml.internal.bind;
    28 import java.math.BigDecimal;
    29 import java.math.BigInteger;
    30 import java.security.AccessController;
    31 import java.security.PrivilegedAction;
    32 import java.util.Calendar;
    33 import java.util.Collections;
    34 import java.util.GregorianCalendar;
    35 import java.util.Map;
    36 import java.util.TimeZone;
    37 import java.util.WeakHashMap;
    39 import javax.xml.bind.DatatypeConverter;
    40 import javax.xml.bind.DatatypeConverterInterface;
    41 import javax.xml.datatype.DatatypeConfigurationException;
    42 import javax.xml.datatype.DatatypeFactory;
    43 import javax.xml.namespace.NamespaceContext;
    44 import javax.xml.namespace.QName;
    45 import javax.xml.stream.XMLStreamException;
    46 import javax.xml.stream.XMLStreamWriter;
    48 /**
    49  * This class is the JAXB RI's default implementation of the
    50  * {@link DatatypeConverterInterface}.
    51  *
    52  * <p>
    53  * When client applications specify the use of the static print/parse
    54  * methods in {@link DatatypeConverter}, it will delegate
    55  * to this class.
    56  *
    57  * <p>
    58  * This class is responsible for whitespace normalization.
    59  *
    60  * @author <ul><li>Ryan Shoemaker, Martin Grebac</li></ul>
    61  * @since JAXB1.0
    62  * @deprecated in JAXB 2.2.4 - use javax.xml.bind.DatatypeConverterImpl instead
    63  * or let us know why you can't
    64  */
    65 @Deprecated
    66 public final class DatatypeConverterImpl implements DatatypeConverterInterface {
    68     @Deprecated
    69     public static final DatatypeConverterInterface theInstance = new DatatypeConverterImpl();
    71     protected DatatypeConverterImpl() {
    72         // shall not be used
    73     }
    75     public static BigInteger _parseInteger(CharSequence s) {
    76         return new BigInteger(removeOptionalPlus(WhiteSpaceProcessor.trim(s)).toString());
    77     }
    79     public static String _printInteger(BigInteger val) {
    80         return val.toString();
    81     }
    83     /**
    84      * Faster but less robust String->int conversion.
    85      *
    86      * Note that:
    87      * <ol>
    88      *  <li>XML Schema allows '+', but {@link Integer#valueOf(String)} is not.
    89      *  <li>XML Schema allows leading and trailing (but not in-between) whitespaces.
    90      *      {@link Integer#valueOf(String)} doesn't allow any.
    91      * </ol>
    92      */
    93     public static int _parseInt(CharSequence s) {
    94         int len = s.length();
    95         int sign = 1;
    97         int r = 0;
    99         for (int i = 0; i < len; i++) {
   100             char ch = s.charAt(i);
   101             if (WhiteSpaceProcessor.isWhiteSpace(ch)) {
   102                 // skip whitespace
   103             } else if ('0' <= ch && ch <= '9') {
   104                 r = r * 10 + (ch - '0');
   105             } else if (ch == '-') {
   106                 sign = -1;
   107             } else if (ch == '+') {
   108                 // noop
   109             } else {
   110                 throw new NumberFormatException("Not a number: " + s);
   111             }
   112         }
   114         return r * sign;
   115     }
   117     public static long _parseLong(CharSequence s) {
   118         return Long.valueOf(removeOptionalPlus(WhiteSpaceProcessor.trim(s)).toString());
   119     }
   121     public static short _parseShort(CharSequence s) {
   122         return (short) _parseInt(s);
   123     }
   125     public static String _printShort(short val) {
   126         return String.valueOf(val);
   127     }
   129     public static BigDecimal _parseDecimal(CharSequence content) {
   130         content = WhiteSpaceProcessor.trim(content);
   132         if (content.length() <= 0) {
   133             return null;
   134         }
   136         return new BigDecimal(content.toString());
   138         // from purely XML Schema perspective,
   139         // this implementation has a problem, since
   140         // in xs:decimal "1.0" and "1" is equal whereas the above
   141         // code will return different values for those two forms.
   142         //
   143         // the code was originally using com.sun.msv.datatype.xsd.NumberType.load,
   144         // but a profiling showed that the process of normalizing "1.0" into "1"
   145         // could take non-trivial time.
   146         //
   147         // also, from the user's point of view, one might be surprised if
   148         // 1 (not 1.0) is returned from "1.000"
   149     }
   151     public static float _parseFloat(CharSequence _val) {
   152         String s = WhiteSpaceProcessor.trim(_val).toString();
   153         /* Incompatibilities of XML Schema's float "xfloat" and Java's float "jfloat"
   155          * jfloat.valueOf ignores leading and trailing whitespaces,
   156         whereas this is not allowed in xfloat.
   157          * jfloat.valueOf allows "float type suffix" (f, F) to be
   158         appended after float literal (e.g., 1.52e-2f), whereare
   159         this is not the case of xfloat.
   161         gray zone
   162         ---------
   163          * jfloat allows ".523". And there is no clear statement that mentions
   164         this case in xfloat. Although probably this is allowed.
   165          *
   166          */
   168         if (s.equals("NaN")) {
   169             return Float.NaN;
   170         }
   171         if (s.equals("INF")) {
   172             return Float.POSITIVE_INFINITY;
   173         }
   174         if (s.equals("-INF")) {
   175             return Float.NEGATIVE_INFINITY;
   176         }
   178         if (s.length() == 0
   179                 || !isDigitOrPeriodOrSign(s.charAt(0))
   180                 || !isDigitOrPeriodOrSign(s.charAt(s.length() - 1))) {
   181             throw new NumberFormatException();
   182         }
   184         // these screening process is necessary due to the wobble of Float.valueOf method
   185         return Float.parseFloat(s);
   186     }
   188     public static String _printFloat(float v) {
   189         if (Float.isNaN(v)) {
   190             return "NaN";
   191         }
   192         if (v == Float.POSITIVE_INFINITY) {
   193             return "INF";
   194         }
   195         if (v == Float.NEGATIVE_INFINITY) {
   196             return "-INF";
   197         }
   198         return String.valueOf(v);
   199     }
   201     public static double _parseDouble(CharSequence _val) {
   202         String val = WhiteSpaceProcessor.trim(_val).toString();
   204         if (val.equals("NaN")) {
   205             return Double.NaN;
   206         }
   207         if (val.equals("INF")) {
   208             return Double.POSITIVE_INFINITY;
   209         }
   210         if (val.equals("-INF")) {
   211             return Double.NEGATIVE_INFINITY;
   212         }
   214         if (val.length() == 0
   215                 || !isDigitOrPeriodOrSign(val.charAt(0))
   216                 || !isDigitOrPeriodOrSign(val.charAt(val.length() - 1))) {
   217             throw new NumberFormatException(val);
   218         }
   221         // these screening process is necessary due to the wobble of Float.valueOf method
   222         return Double.parseDouble(val);
   223     }
   225     public static Boolean _parseBoolean(CharSequence literal) {
   226         if (literal == null) {
   227             return null;
   228         }
   230         int i = 0;
   231         int len = literal.length();
   232         char ch;
   233         boolean value = false;
   235         if (literal.length() <= 0) {
   236             return null;
   237         }
   239         do {
   240             ch = literal.charAt(i++);
   241         } while (WhiteSpaceProcessor.isWhiteSpace(ch) && i < len);
   243         int strIndex = 0;
   245         switch (ch) {
   246             case '1':
   247                 value = true;
   248                 break;
   249             case '0':
   250                 value = false;
   251                 break;
   252             case 't':
   253                 String strTrue = "rue";
   254                 do {
   255                     ch = literal.charAt(i++);
   256                 } while ((strTrue.charAt(strIndex++) == ch) && i < len && strIndex < 3);
   258                 if (strIndex == 3) {
   259                     value = true;
   260                 } else {
   261                     return false;
   262                 }
   263 //                    throw new IllegalArgumentException("String \"" + literal + "\" is not valid boolean value.");
   265                 break;
   266             case 'f':
   267                 String strFalse = "alse";
   268                 do {
   269                     ch = literal.charAt(i++);
   270                 } while ((strFalse.charAt(strIndex++) == ch) && i < len && strIndex < 4);
   273                 if (strIndex == 4) {
   274                     value = false;
   275                 } else {
   276                     return false;
   277                 }
   278 //                    throw new IllegalArgumentException("String \"" + literal + "\" is not valid boolean value.");
   280                 break;
   281         }
   283         if (i < len) {
   284             do {
   285                 ch = literal.charAt(i++);
   286             } while (WhiteSpaceProcessor.isWhiteSpace(ch) && i < len);
   287         }
   289         if (i == len) {
   290             return value;
   291         } else {
   292             return null;
   293         }
   294 //            throw new IllegalArgumentException("String \"" + literal + "\" is not valid boolean value.");
   295     }
   297     public static String _printBoolean(boolean val) {
   298         return val ? "true" : "false";
   299     }
   301     public static byte _parseByte(CharSequence literal) {
   302         return (byte) _parseInt(literal);
   303     }
   305     public static String _printByte(byte val) {
   306         return String.valueOf(val);
   307     }
   309     /**
   310      * @return null if fails to convert.
   311      */
   312     public static QName _parseQName(CharSequence text, NamespaceContext nsc) {
   313         int length = text.length();
   315         // trim whitespace
   316         int start = 0;
   317         while (start < length && WhiteSpaceProcessor.isWhiteSpace(text.charAt(start))) {
   318             start++;
   319         }
   321         int end = length;
   322         while (end > start && WhiteSpaceProcessor.isWhiteSpace(text.charAt(end - 1))) {
   323             end--;
   324         }
   326         if (end == start) {
   327             throw new IllegalArgumentException("input is empty");
   328         }
   331         String uri;
   332         String localPart;
   333         String prefix;
   335         // search ':'
   336         int idx = start + 1;    // no point in searching the first char. that's not valid.
   337         while (idx < end && text.charAt(idx) != ':') {
   338             idx++;
   339         }
   341         if (idx == end) {
   342             uri = nsc.getNamespaceURI("");
   343             localPart = text.subSequence(start, end).toString();
   344             prefix = "";
   345         } else {
   346             // Prefix exists, check everything
   347             prefix = text.subSequence(start, idx).toString();
   348             localPart = text.subSequence(idx + 1, end).toString();
   349             uri = nsc.getNamespaceURI(prefix);
   350             // uri can never be null according to javadoc,
   351             // but some users reported that there are implementations that return null.
   352             if (uri == null || uri.length() == 0) // crap. the NamespaceContext interface is broken.
   353             // error: unbound prefix
   354             {
   355                 throw new IllegalArgumentException("prefix " + prefix + " is not bound to a namespace");
   356             }
   357         }
   359         return new QName(uri, localPart, prefix);
   360     }
   362     public static GregorianCalendar _parseDateTime(CharSequence s) {
   363         String val = WhiteSpaceProcessor.trim(s).toString();
   364         return getDatatypeFactory().newXMLGregorianCalendar(val).toGregorianCalendar();
   365     }
   367     public static String _printDateTime(Calendar val) {
   368         return CalendarFormatter.doFormat("%Y-%M-%DT%h:%m:%s%z", val);
   369     }
   371     public static String _printDate(Calendar val) {
   372         return CalendarFormatter.doFormat((new StringBuilder("%Y-%M-%D").append("%z")).toString(),val);
   373     }
   375     public static String _printInt(int val) {
   376         return String.valueOf(val);
   377     }
   379     public static String _printLong(long val) {
   380         return String.valueOf(val);
   381     }
   383     public static String _printDecimal(BigDecimal val) {
   384         return val.toPlainString();
   385     }
   387     public static String _printDouble(double v) {
   388         if (Double.isNaN(v)) {
   389             return "NaN";
   390         }
   391         if (v == Double.POSITIVE_INFINITY) {
   392             return "INF";
   393         }
   394         if (v == Double.NEGATIVE_INFINITY) {
   395             return "-INF";
   396         }
   397         return String.valueOf(v);
   398     }
   400     public static String _printQName(QName val, NamespaceContext nsc) {
   401         // Double-check
   402         String qname;
   403         String prefix = nsc.getPrefix(val.getNamespaceURI());
   404         String localPart = val.getLocalPart();
   406         if (prefix == null || prefix.length() == 0) { // be defensive
   407             qname = localPart;
   408         } else {
   409             qname = prefix + ':' + localPart;
   410         }
   412         return qname;
   413     }
   415 // base64 decoder
   416     private static final byte[] decodeMap = initDecodeMap();
   417     private static final byte PADDING = 127;
   419     private static byte[] initDecodeMap() {
   420         byte[] map = new byte[128];
   421         int i;
   422         for (i = 0; i < 128; i++) {
   423             map[i] = -1;
   424         }
   426         for (i = 'A'; i <= 'Z'; i++) {
   427             map[i] = (byte) (i - 'A');
   428         }
   429         for (i = 'a'; i <= 'z'; i++) {
   430             map[i] = (byte) (i - 'a' + 26);
   431         }
   432         for (i = '0'; i <= '9'; i++) {
   433             map[i] = (byte) (i - '0' + 52);
   434         }
   435         map['+'] = 62;
   436         map['/'] = 63;
   437         map['='] = PADDING;
   439         return map;
   440     }
   442     /**
   443      * computes the length of binary data speculatively.
   444      *
   445      * <p>
   446      * Our requirement is to create byte[] of the exact length to store the binary data.
   447      * If we do this in a straight-forward way, it takes two passes over the data.
   448      * Experiments show that this is a non-trivial overhead (35% or so is spent on
   449      * the first pass in calculating the length.)
   450      *
   451      * <p>
   452      * So the approach here is that we compute the length speculatively, without looking
   453      * at the whole contents. The obtained speculative value is never less than the
   454      * actual length of the binary data, but it may be bigger. So if the speculation
   455      * goes wrong, we'll pay the cost of reallocation and buffer copying.
   456      *
   457      * <p>
   458      * If the base64 text is tightly packed with no indentation nor illegal char
   459      * (like what most web services produce), then the speculation of this method
   460      * will be correct, so we get the performance benefit.
   461      */
   462     private static int guessLength(String text) {
   463         final int len = text.length();
   465         // compute the tail '=' chars
   466         int j = len - 1;
   467         for (; j >= 0; j--) {
   468             byte code = decodeMap[text.charAt(j)];
   469             if (code == PADDING) {
   470                 continue;
   471             }
   472             if (code == -1) // most likely this base64 text is indented. go with the upper bound
   473             {
   474                 return text.length() / 4 * 3;
   475             }
   476             break;
   477         }
   479         j++;    // text.charAt(j) is now at some base64 char, so +1 to make it the size
   480         int padSize = len - j;
   481         if (padSize > 2) // something is wrong with base64. be safe and go with the upper bound
   482         {
   483             return text.length() / 4 * 3;
   484         }
   486         // so far this base64 looks like it's unindented tightly packed base64.
   487         // take a chance and create an array with the expected size
   488         return text.length() / 4 * 3 - padSize;
   489     }
   491     /**
   492      * @param text
   493      *      base64Binary data is likely to be long, and decoding requires
   494      *      each character to be accessed twice (once for counting length, another
   495      *      for decoding.)
   496      *
   497      *      A benchmark showed that taking {@link String} is faster, presumably
   498      *      because JIT can inline a lot of string access (with data of 1K chars, it was twice as fast)
   499      */
   500     public static byte[] _parseBase64Binary(String text) {
   501         final int buflen = guessLength(text);
   502         final byte[] out = new byte[buflen];
   503         int o = 0;
   505         final int len = text.length();
   506         int i;
   508         final byte[] quadruplet = new byte[4];
   509         int q = 0;
   511         // convert each quadruplet to three bytes.
   512         for (i = 0; i < len; i++) {
   513             char ch = text.charAt(i);
   514             byte v = decodeMap[ch];
   516             if (v != -1) {
   517                 quadruplet[q++] = v;
   518             }
   520             if (q == 4) {
   521                 // quadruplet is now filled.
   522                 out[o++] = (byte) ((quadruplet[0] << 2) | (quadruplet[1] >> 4));
   523                 if (quadruplet[2] != PADDING) {
   524                     out[o++] = (byte) ((quadruplet[1] << 4) | (quadruplet[2] >> 2));
   525                 }
   526                 if (quadruplet[3] != PADDING) {
   527                     out[o++] = (byte) ((quadruplet[2] << 6) | (quadruplet[3]));
   528                 }
   529                 q = 0;
   530             }
   531         }
   533         if (buflen == o) // speculation worked out to be OK
   534         {
   535             return out;
   536         }
   538         // we overestimated, so need to create a new buffer
   539         byte[] nb = new byte[o];
   540         System.arraycopy(out, 0, nb, 0, o);
   541         return nb;
   542     }
   543     private static final char[] encodeMap = initEncodeMap();
   545     private static char[] initEncodeMap() {
   546         char[] map = new char[64];
   547         int i;
   548         for (i = 0; i < 26; i++) {
   549             map[i] = (char) ('A' + i);
   550         }
   551         for (i = 26; i < 52; i++) {
   552             map[i] = (char) ('a' + (i - 26));
   553         }
   554         for (i = 52; i < 62; i++) {
   555             map[i] = (char) ('0' + (i - 52));
   556         }
   557         map[62] = '+';
   558         map[63] = '/';
   560         return map;
   561     }
   563     public static char encode(int i) {
   564         return encodeMap[i & 0x3F];
   565     }
   567     public static byte encodeByte(int i) {
   568         return (byte) encodeMap[i & 0x3F];
   569     }
   571     public static String _printBase64Binary(byte[] input) {
   572         return _printBase64Binary(input, 0, input.length);
   573     }
   575     public static String _printBase64Binary(byte[] input, int offset, int len) {
   576         char[] buf = new char[((len + 2) / 3) * 4];
   577         int ptr = _printBase64Binary(input, offset, len, buf, 0);
   578         assert ptr == buf.length;
   579         return new String(buf);
   580     }
   582     /**
   583      * Encodes a byte array into a char array by doing base64 encoding.
   584      *
   585      * The caller must supply a big enough buffer.
   586      *
   587      * @return
   588      *      the value of {@code ptr+((len+2)/3)*4}, which is the new offset
   589      *      in the output buffer where the further bytes should be placed.
   590      */
   591     public static int _printBase64Binary(byte[] input, int offset, int len, char[] buf, int ptr) {
   592         // encode elements until only 1 or 2 elements are left to encode
   593         int remaining = len;
   594         int i;
   595         for (i = offset;remaining >= 3; remaining -= 3, i += 3) {
   596             buf[ptr++] = encode(input[i] >> 2);
   597             buf[ptr++] = encode(
   598                     ((input[i] & 0x3) << 4)
   599                     | ((input[i + 1] >> 4) & 0xF));
   600             buf[ptr++] = encode(
   601                     ((input[i + 1] & 0xF) << 2)
   602                     | ((input[i + 2] >> 6) & 0x3));
   603             buf[ptr++] = encode(input[i + 2] & 0x3F);
   604         }
   605         // encode when exactly 1 element (left) to encode
   606         if (remaining == 1) {
   607             buf[ptr++] = encode(input[i] >> 2);
   608             buf[ptr++] = encode(((input[i]) & 0x3) << 4);
   609             buf[ptr++] = '=';
   610             buf[ptr++] = '=';
   611         }
   612         // encode when exactly 2 elements (left) to encode
   613         if (remaining == 2) {
   614             buf[ptr++] = encode(input[i] >> 2);
   615             buf[ptr++] = encode(((input[i] & 0x3) << 4)
   616                     | ((input[i + 1] >> 4) & 0xF));
   617             buf[ptr++] = encode((input[i + 1] & 0xF) << 2);
   618             buf[ptr++] = '=';
   619         }
   620         return ptr;
   621     }
   623     public static void _printBase64Binary(byte[] input, int offset, int len, XMLStreamWriter output) throws XMLStreamException {
   624         int remaining = len;
   625         int i;
   626         char[] buf = new char[4];
   628         for (i = offset; remaining >= 3; remaining -= 3, i += 3) {
   629             buf[0] = encode(input[i] >> 2);
   630             buf[1] = encode(
   631                     ((input[i] & 0x3) << 4)
   632                     | ((input[i + 1] >> 4) & 0xF));
   633             buf[2] = encode(
   634                     ((input[i + 1] & 0xF) << 2)
   635                     | ((input[i + 2] >> 6) & 0x3));
   636             buf[3] = encode(input[i + 2] & 0x3F);
   637             output.writeCharacters(buf, 0, 4);
   638         }
   639         // encode when exactly 1 element (left) to encode
   640         if (remaining == 1) {
   641             buf[0] = encode(input[i] >> 2);
   642             buf[1] = encode(((input[i]) & 0x3) << 4);
   643             buf[2] = '=';
   644             buf[3] = '=';
   645             output.writeCharacters(buf, 0, 4);
   646         }
   647         // encode when exactly 2 elements (left) to encode
   648         if (remaining == 2) {
   649             buf[0] = encode(input[i] >> 2);
   650             buf[1] = encode(((input[i] & 0x3) << 4)
   651                     | ((input[i + 1] >> 4) & 0xF));
   652             buf[2] = encode((input[i + 1] & 0xF) << 2);
   653             buf[3] = '=';
   654             output.writeCharacters(buf, 0, 4);
   655         }
   656     }
   658     /**
   659      * Encodes a byte array into another byte array by first doing base64 encoding
   660      * then encoding the result in ASCII.
   661      *
   662      * The caller must supply a big enough buffer.
   663      *
   664      * @return
   665      *      the value of {@code ptr+((len+2)/3)*4}, which is the new offset
   666      *      in the output buffer where the further bytes should be placed.
   667      */
   668     public static int _printBase64Binary(byte[] input, int offset, int len, byte[] out, int ptr) {
   669         byte[] buf = out;
   670         int remaining = len;
   671         int i;
   672         for (i=offset; remaining >= 3; remaining -= 3, i += 3 ) {
   673             buf[ptr++] = encodeByte(input[i]>>2);
   674             buf[ptr++] = encodeByte(
   675                         ((input[i]&0x3)<<4) |
   676                         ((input[i+1]>>4)&0xF));
   677             buf[ptr++] = encodeByte(
   678                         ((input[i+1]&0xF)<<2)|
   679                         ((input[i+2]>>6)&0x3));
   680             buf[ptr++] = encodeByte(input[i+2]&0x3F);
   681         }
   682         // encode when exactly 1 element (left) to encode
   683         if (remaining == 1) {
   684             buf[ptr++] = encodeByte(input[i]>>2);
   685             buf[ptr++] = encodeByte(((input[i])&0x3)<<4);
   686             buf[ptr++] = '=';
   687             buf[ptr++] = '=';
   688         }
   689         // encode when exactly 2 elements (left) to encode
   690         if (remaining == 2) {
   691             buf[ptr++] = encodeByte(input[i]>>2);
   692             buf[ptr++] = encodeByte(
   693                         ((input[i]&0x3)<<4) |
   694                         ((input[i+1]>>4)&0xF));
   695             buf[ptr++] = encodeByte((input[i+1]&0xF)<<2);
   696             buf[ptr++] = '=';
   697         }
   699         return ptr;
   700     }
   702     private static CharSequence removeOptionalPlus(CharSequence s) {
   703         int len = s.length();
   705         if (len <= 1 || s.charAt(0) != '+') {
   706             return s;
   707         }
   709         s = s.subSequence(1, len);
   710         char ch = s.charAt(0);
   711         if ('0' <= ch && ch <= '9') {
   712             return s;
   713         }
   714         if ('.' == ch) {
   715             return s;
   716         }
   718         throw new NumberFormatException();
   719     }
   721     private static boolean isDigitOrPeriodOrSign(char ch) {
   722         if ('0' <= ch && ch <= '9') {
   723             return true;
   724         }
   725         if (ch == '+' || ch == '-' || ch == '.') {
   726             return true;
   727         }
   728         return false;
   729     }
   731     private static final Map<ClassLoader, DatatypeFactory> DF_CACHE = Collections.synchronizedMap(new WeakHashMap<ClassLoader, DatatypeFactory>());
   733     public static DatatypeFactory getDatatypeFactory() {
   734         ClassLoader tccl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
   735             public ClassLoader run() {
   736                 return Thread.currentThread().getContextClassLoader();
   737             }
   738         });
   739         DatatypeFactory df = DF_CACHE.get(tccl);
   740         if (df == null) {
   741             synchronized (DatatypeConverterImpl.class) {
   742                 df = DF_CACHE.get(tccl);
   743                 if (df == null) { // to prevent multiple initialization
   744                     try {
   745                         df = DatatypeFactory.newInstance();
   746                     } catch (DatatypeConfigurationException e) {
   747                         throw new Error(Messages.FAILED_TO_INITIALE_DATATYPE_FACTORY.format(),e);
   748                     }
   749                     DF_CACHE.put(tccl, df);
   750                 }
   751             }
   752         }
   753         return df;
   754     }
   756     private static final class CalendarFormatter {
   758         public static String doFormat(String format, Calendar cal) throws IllegalArgumentException {
   759             int fidx = 0;
   760             int flen = format.length();
   761             StringBuilder buf = new StringBuilder();
   763             while (fidx < flen) {
   764                 char fch = format.charAt(fidx++);
   766                 if (fch != '%') {  // not a meta character
   767                     buf.append(fch);
   768                     continue;
   769                 }
   771                 // seen meta character. we don't do error check against the format
   772                 switch (format.charAt(fidx++)) {
   773                     case 'Y': // year
   774                         formatYear(cal, buf);
   775                         break;
   777                     case 'M': // month
   778                         formatMonth(cal, buf);
   779                         break;
   781                     case 'D': // days
   782                         formatDays(cal, buf);
   783                         break;
   785                     case 'h': // hours
   786                         formatHours(cal, buf);
   787                         break;
   789                     case 'm': // minutes
   790                         formatMinutes(cal, buf);
   791                         break;
   793                     case 's': // parse seconds.
   794                         formatSeconds(cal, buf);
   795                         break;
   797                     case 'z': // time zone
   798                         formatTimeZone(cal, buf);
   799                         break;
   801                     default:
   802                         // illegal meta character. impossible.
   803                         throw new InternalError();
   804                 }
   805             }
   807             return buf.toString();
   808         }
   810         private static void formatYear(Calendar cal, StringBuilder buf) {
   811             int year = cal.get(Calendar.YEAR);
   813             String s;
   814             if (year <= 0) // negative value
   815             {
   816                 s = Integer.toString(1 - year);
   817             } else // positive value
   818             {
   819                 s = Integer.toString(year);
   820             }
   822             while (s.length() < 4) {
   823                 s = '0' + s;
   824             }
   825             if (year <= 0) {
   826                 s = '-' + s;
   827             }
   829             buf.append(s);
   830         }
   832         private static void formatMonth(Calendar cal, StringBuilder buf) {
   833             formatTwoDigits(cal.get(Calendar.MONTH) + 1, buf);
   834         }
   836         private static void formatDays(Calendar cal, StringBuilder buf) {
   837             formatTwoDigits(cal.get(Calendar.DAY_OF_MONTH), buf);
   838         }
   840         private static void formatHours(Calendar cal, StringBuilder buf) {
   841             formatTwoDigits(cal.get(Calendar.HOUR_OF_DAY), buf);
   842         }
   844         private static void formatMinutes(Calendar cal, StringBuilder buf) {
   845             formatTwoDigits(cal.get(Calendar.MINUTE), buf);
   846         }
   848         private static void formatSeconds(Calendar cal, StringBuilder buf) {
   849             formatTwoDigits(cal.get(Calendar.SECOND), buf);
   850             if (cal.isSet(Calendar.MILLISECOND)) { // milliseconds
   851                 int n = cal.get(Calendar.MILLISECOND);
   852                 if (n != 0) {
   853                     String ms = Integer.toString(n);
   854                     while (ms.length() < 3) {
   855                         ms = '0' + ms; // left 0 paddings.
   856                     }
   857                     buf.append('.');
   858                     buf.append(ms);
   859                 }
   860             }
   861         }
   863         /** formats time zone specifier. */
   864         private static void formatTimeZone(Calendar cal, StringBuilder buf) {
   865             TimeZone tz = cal.getTimeZone();
   867             if (tz == null) {
   868                 return;
   869             }
   871             // otherwise print out normally.
   872             int offset = tz.getOffset(cal.getTime().getTime());
   874             if (offset == 0) {
   875                 buf.append('Z');
   876                 return;
   877             }
   879             if (offset >= 0) {
   880                 buf.append('+');
   881             } else {
   882                 buf.append('-');
   883                 offset *= -1;
   884             }
   886             offset /= 60 * 1000; // offset is in milli-seconds
   888             formatTwoDigits(offset / 60, buf);
   889             buf.append(':');
   890             formatTwoDigits(offset % 60, buf);
   891         }
   893         /** formats Integer into two-character-wide string. */
   894         private static void formatTwoDigits(int n, StringBuilder buf) {
   895             // n is always non-negative.
   896             if (n < 10) {
   897                 buf.append('0');
   898             }
   899             buf.append(n);
   900         }
   901     }
   903     // DEPRECATED METHODS, KEPT FOR JAXB1 GENERATED CLASSES COMPATIBILITY, WILL BE REMOVED IN FUTURE
   905     @Deprecated
   906     public String parseString(String lexicalXSDString) {
   907         return lexicalXSDString;
   908     }
   910     @Deprecated
   911     public BigInteger parseInteger(String lexicalXSDInteger) {
   912         return _parseInteger(lexicalXSDInteger);
   913     }
   915     @Deprecated
   916     public String printInteger(BigInteger val) {
   917         return _printInteger(val);
   918     }
   920     @Deprecated
   921     public int parseInt(String s) {
   922         return _parseInt(s);
   923     }
   925     @Deprecated
   926     public long parseLong(String lexicalXSLong) {
   927         return _parseLong(lexicalXSLong);
   928     }
   930     @Deprecated
   931     public short parseShort(String lexicalXSDShort) {
   932         return _parseShort(lexicalXSDShort);
   933     }
   935     @Deprecated
   936     public String printShort(short val) {
   937         return _printShort(val);
   938     }
   940     @Deprecated
   941     public BigDecimal parseDecimal(String content) {
   942         return _parseDecimal(content);
   943     }
   945     @Deprecated
   946     public float parseFloat(String lexicalXSDFloat) {
   947         return _parseFloat(lexicalXSDFloat);
   948     }
   950     @Deprecated
   951     public String printFloat(float v) {
   952         return _printFloat(v);
   953     }
   955     @Deprecated
   956     public double parseDouble(String lexicalXSDDouble) {
   957         return _parseDouble(lexicalXSDDouble);
   958     }
   960     @Deprecated
   961     public boolean parseBoolean(String lexicalXSDBoolean) {
   962         Boolean b = _parseBoolean(lexicalXSDBoolean);
   963         return (b == null) ? false : b.booleanValue();
   964     }
   966     @Deprecated
   967     public String printBoolean(boolean val) {
   968         return val ? "true" : "false";
   969     }
   971     @Deprecated
   972     public byte parseByte(String lexicalXSDByte) {
   973         return _parseByte(lexicalXSDByte);
   974     }
   976     @Deprecated
   977     public String printByte(byte val) {
   978         return _printByte(val);
   979     }
   981     @Deprecated
   982     public QName parseQName(String lexicalXSDQName, NamespaceContext nsc) {
   983         return _parseQName(lexicalXSDQName, nsc);
   984     }
   986     @Deprecated
   987     public Calendar parseDateTime(String lexicalXSDDateTime) {
   988         return _parseDateTime(lexicalXSDDateTime);
   989     }
   991     @Deprecated
   992     public String printDateTime(Calendar val) {
   993         return _printDateTime(val);
   994     }
   996     @Deprecated
   997     public byte[] parseBase64Binary(String lexicalXSDBase64Binary) {
   998         return _parseBase64Binary(lexicalXSDBase64Binary);
   999     }
  1001     @Deprecated
  1002     public byte[] parseHexBinary(String s) {
  1003         final int len = s.length();
  1005         // "111" is not a valid hex encoding.
  1006         if (len % 2 != 0) {
  1007             throw new IllegalArgumentException("hexBinary needs to be even-length: " + s);
  1010         byte[] out = new byte[len / 2];
  1012         for (int i = 0; i < len; i += 2) {
  1013             int h = hexToBin(s.charAt(i));
  1014             int l = hexToBin(s.charAt(i + 1));
  1015             if (h == -1 || l == -1) {
  1016                 throw new IllegalArgumentException("contains illegal character for hexBinary: " + s);
  1019             out[i / 2] = (byte) (h * 16 + l);
  1022         return out;
  1025     @Deprecated
  1026     private static int hexToBin(char ch) {
  1027         if ('0' <= ch && ch <= '9') {
  1028             return ch - '0';
  1030         if ('A' <= ch && ch <= 'F') {
  1031             return ch - 'A' + 10;
  1033         if ('a' <= ch && ch <= 'f') {
  1034             return ch - 'a' + 10;
  1036         return -1;
  1039     @Deprecated
  1040     private static final char[] hexCode = "0123456789ABCDEF".toCharArray();
  1042     @Deprecated
  1043     public String printHexBinary(byte[] data) {
  1044         StringBuilder r = new StringBuilder(data.length * 2);
  1045         for (byte b : data) {
  1046             r.append(hexCode[(b >> 4) & 0xF]);
  1047             r.append(hexCode[(b & 0xF)]);
  1049         return r.toString();
  1052     @Deprecated
  1053     public long parseUnsignedInt(String lexicalXSDUnsignedInt) {
  1054         return _parseLong(lexicalXSDUnsignedInt);
  1057     @Deprecated
  1058     public String printUnsignedInt(long val) {
  1059         return _printLong(val);
  1062     @Deprecated
  1063     public int parseUnsignedShort(String lexicalXSDUnsignedShort) {
  1064         return _parseInt(lexicalXSDUnsignedShort);
  1067     @Deprecated
  1068     public Calendar parseTime(String lexicalXSDTime) {
  1069         return getDatatypeFactory().newXMLGregorianCalendar(lexicalXSDTime).toGregorianCalendar();
  1072     @Deprecated
  1073     public String printTime(Calendar val) {
  1074         return CalendarFormatter.doFormat("%h:%m:%s%z", val);
  1077     @Deprecated
  1078     public Calendar parseDate(String lexicalXSDDate) {
  1079         return getDatatypeFactory().newXMLGregorianCalendar(lexicalXSDDate).toGregorianCalendar();
  1082     @Deprecated
  1083     public String printDate(Calendar val) {
  1084         return _printDate(val);
  1087     @Deprecated
  1088     public String parseAnySimpleType(String lexicalXSDAnySimpleType) {
  1089         return lexicalXSDAnySimpleType;
  1092     @Deprecated
  1093     public String printString(String val) {
  1094         return val;
  1097     @Deprecated
  1098     public String printInt(int val) {
  1099         return _printInt(val);
  1102     @Deprecated
  1103     public String printLong(long val) {
  1104         return _printLong(val);
  1107     @Deprecated
  1108     public String printDecimal(BigDecimal val) {
  1109         return _printDecimal(val);
  1112     @Deprecated
  1113     public String printDouble(double v) {
  1114         return _printDouble(v);
  1117     @Deprecated
  1118     public String printQName(QName val, NamespaceContext nsc) {
  1119         return _printQName(val, nsc);
  1122     @Deprecated
  1123     public String printBase64Binary(byte[] val) {
  1124         return _printBase64Binary(val);
  1127     @Deprecated
  1128     public String printUnsignedShort(int val) {
  1129         return String.valueOf(val);
  1132     @Deprecated
  1133     public String printAnySimpleType(String val) {
  1134         return val;

mercurial