Save This Page
Home » Open-JDK-6.b17-src » com.sun.xml.internal » bind » [javadoc | source]
    1   /*
    2    * Copyright 2005-2006 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package com.sun.xml.internal.bind;
   26   
   27   import java.math.BigDecimal;
   28   import java.math.BigInteger;
   29   import java.util.Calendar;
   30   import java.util.GregorianCalendar;
   31   import java.util.TimeZone;
   32   
   33   import javax.xml.bind.DatatypeConverter;
   34   import javax.xml.bind.DatatypeConverterInterface;
   35   import javax.xml.datatype.DatatypeConfigurationException;
   36   import javax.xml.datatype.DatatypeFactory;
   37   import javax.xml.namespace.NamespaceContext;
   38   import javax.xml.namespace.QName;
   39   
   40   import com.sun.xml.internal.bind.v2.TODO;
   41   
   42   /**
   43    * This class is the JAXB RI's default implementation of the
   44    * {@link DatatypeConverterInterface}.
   45    *
   46    * <p>
   47    * When client apps specify the use of the static print/parse
   48    * methods in {@link DatatypeConverter}, it will delegate
   49    * to this class.
   50    *
   51    * <p>
   52    * This class is responsible for whitespace normalization.
   53    *
   54    * @author <ul><li>Ryan Shoemaker, Sun Microsystems, Inc.</li></ul>
   55    * @since JAXB1.0
   56    */
   57   public final class DatatypeConverterImpl implements DatatypeConverterInterface {
   58   
   59       /**
   60        * To avoid re-creating instances, we cache one instance.
   61        */
   62       public static final DatatypeConverterInterface theInstance = new DatatypeConverterImpl();
   63   
   64       protected DatatypeConverterImpl() {
   65       }
   66   
   67       public String parseString(String lexicalXSDString) {
   68           return lexicalXSDString;
   69       }
   70   
   71       public BigInteger parseInteger(String lexicalXSDInteger) {
   72           return _parseInteger(lexicalXSDInteger);
   73       }
   74   
   75       public static BigInteger _parseInteger(CharSequence s) {
   76           return new BigInteger(removeOptionalPlus(WhiteSpaceProcessor.trim(s)).toString());
   77       }
   78   
   79       public String printInteger(BigInteger val) {
   80           return _printInteger(val);
   81       }
   82   
   83       public static String _printInteger(BigInteger val) {
   84           return val.toString();
   85       }
   86   
   87       public int parseInt(String s) {
   88           return _parseInt(s);
   89       }
   90   
   91       /**
   92        * Faster but less robust String->int conversion.
   93        *
   94        * Note that:
   95        * <ol>
   96        *  <li>XML Schema allows '+', but {@link Integer#valueOf(String)} is not.
   97        *  <li>XML Schema allows leading and trailing (but not in-between) whitespaces..
   98        *      {@link Integer#valueOf(String)} doesn't allow any.
   99        * </ol>
  100        */
  101       public static int _parseInt(CharSequence s) {
  102           int len = s.length();
  103           int sign = 1;
  104   
  105           int r = 0;
  106   
  107           for( int i=0; i<len; i++ ) {
  108               char ch = s.charAt(i);
  109               if(WhiteSpaceProcessor.isWhiteSpace(ch)) {
  110                   // skip whitespace
  111               } else
  112               if('0'<=ch && ch<='9') {
  113                   r = r*10 + (ch-'0');
  114               } else
  115               if(ch=='-') {
  116                   sign = -1;
  117               } else
  118               if(ch=='+') {
  119                   // noop
  120               } else
  121                   throw new NumberFormatException("Not a number: "+s);
  122           }
  123   
  124           return r*sign;
  125       }
  126   
  127       public long parseLong(String lexicalXSLong) {
  128           return _parseLong(lexicalXSLong);
  129       }
  130   
  131       public static long _parseLong(CharSequence s) {
  132           return Long.valueOf(removeOptionalPlus(WhiteSpaceProcessor.trim(s)).toString());
  133       }
  134   
  135       public short parseShort(String lexicalXSDShort) {
  136           return _parseShort(lexicalXSDShort);
  137       }
  138   
  139       public static short _parseShort(CharSequence s) {
  140           return (short)_parseInt(s);
  141       }
  142   
  143       public String printShort(short val) {
  144           return _printShort(val);
  145       }
  146   
  147       public static String _printShort(short val) {
  148           return String.valueOf(val);
  149       }
  150   
  151       public BigDecimal parseDecimal(String content) {
  152           return _parseDecimal(content);
  153       }
  154       public static BigDecimal _parseDecimal(CharSequence content) {
  155           content = WhiteSpaceProcessor.trim(content);
  156   
  157           return new BigDecimal(content.toString());
  158   
  159           // from purely XML Schema perspective,
  160           // this implementation has a problem, since
  161           // in xs:decimal "1.0" and "1" is equal whereas the above
  162           // code will return different values for those two forms.
  163           //
  164           // the code was originally using com.sun.msv.datatype.xsd.NumberType.load,
  165           // but a profiling showed that the process of normalizing "1.0" into "1"
  166           // could take non-trivial time.
  167           //
  168           // also, from the user's point of view, one might be surprised if
  169           // 1 (not 1.0) is returned from "1.000"
  170       }
  171   
  172       public float parseFloat(String lexicalXSDFloat) {
  173           return _parseFloat(lexicalXSDFloat);
  174       }
  175   
  176       public static float _parseFloat( CharSequence _val ) {
  177           String s = WhiteSpaceProcessor.trim(_val).toString();
  178           /* Incompatibilities of XML Schema's float "xfloat" and Java's float "jfloat"
  179   
  180               * jfloat.valueOf ignores leading and trailing whitespaces,
  181                 whereas this is not allowed in xfloat.
  182               * jfloat.valueOf allows "float type suffix" (f, F) to be
  183                 appended after float literal (e.g., 1.52e-2f), whereare
  184                 this is not the case of xfloat.
  185   
  186               gray zone
  187               ---------
  188               * jfloat allows ".523". And there is no clear statement that mentions
  189                 this case in xfloat. Although probably this is allowed.
  190               *
  191           */
  192   
  193           if(s.equals("NaN"))         return Float.NaN;
  194           if(s.equals("INF"))         return Float.POSITIVE_INFINITY;
  195           if(s.equals("-INF"))        return Float.NEGATIVE_INFINITY;
  196   
  197           if(s.length()==0
  198           || !isDigitOrPeriodOrSign(s.charAt(0))
  199           || !isDigitOrPeriodOrSign(s.charAt(s.length()-1)) )
  200               throw new NumberFormatException();
  201   
  202           // these screening process is necessary due to the wobble of Float.valueOf method
  203           return Float.parseFloat(s);
  204       }
  205   
  206       public String printFloat(float v) {
  207           return _printFloat(v);
  208       }
  209   
  210       public static String _printFloat(float v) {
  211           if( Float.isNaN(v) )                return "NaN";
  212           if( v==Float.POSITIVE_INFINITY )    return "INF";
  213           if( v==Float.NEGATIVE_INFINITY )    return "-INF";
  214           return String.valueOf(v);
  215       }
  216   
  217   
  218   
  219       public double parseDouble(String lexicalXSDDouble) {
  220           return _parseDouble(lexicalXSDDouble);
  221       }
  222   
  223       public static double _parseDouble( CharSequence _val ) {
  224           String val = WhiteSpaceProcessor.trim(_val).toString();
  225   
  226           if(val.equals("NaN"))    return Double.NaN;
  227           if(val.equals("INF"))    return Double.POSITIVE_INFINITY;
  228           if(val.equals("-INF"))    return Double.NEGATIVE_INFINITY;
  229   
  230           if(val.length()==0
  231           || !isDigitOrPeriodOrSign(val.charAt(0))
  232           || !isDigitOrPeriodOrSign(val.charAt(val.length()-1)) )
  233               throw new NumberFormatException(val);
  234   
  235   
  236           // these screening process is necessary due to the wobble of Float.valueOf method
  237           return Double.parseDouble(val);
  238       }
  239   
  240       public boolean parseBoolean(String lexicalXSDBoolean) {
  241           return _parseBoolean(lexicalXSDBoolean);
  242       }
  243   
  244       public static Boolean _parseBoolean(CharSequence literal) {
  245           int i=0;
  246           int len = literal.length();
  247           char ch;
  248           if (literal.length() <= 0) {
  249               return null;
  250           }
  251           do {
  252               ch = literal.charAt(i++);
  253           } while(WhiteSpaceProcessor.isWhiteSpace(ch) && i<len);
  254   
  255           // if we are strict about errors, check i==len. and report an error
  256           if( ch=='t' || ch=='1' )        return true;
  257           if( ch=='f' || ch=='0' )        return false;
  258           TODO.checkSpec("issue #42");
  259           return false;
  260       }
  261   
  262       public String printBoolean(boolean val) {
  263           return val?"true":"false";
  264       }
  265       public static String _printBoolean(boolean val) {
  266           return val?"true":"false";
  267       }
  268   
  269       public byte parseByte(String lexicalXSDByte) {
  270           return _parseByte(lexicalXSDByte);
  271       }
  272   
  273       public static byte _parseByte(CharSequence literal) {
  274           return (byte)_parseInt(literal);
  275       }
  276   
  277       public String printByte(byte val) {
  278           return _printByte(val);
  279       }
  280   
  281       public static String _printByte(byte val) {
  282           return String.valueOf(val);
  283       }
  284   
  285       public QName parseQName(String lexicalXSDQName, NamespaceContext nsc) {
  286           return _parseQName(lexicalXSDQName,nsc);
  287       }
  288   
  289       /**
  290        * @return null if fails to convert.
  291        */
  292       public static QName _parseQName(CharSequence text, NamespaceContext nsc) {
  293           int length = text.length();
  294   
  295           // trim whitespace
  296           int start=0;
  297           while(start<length && WhiteSpaceProcessor.isWhiteSpace(text.charAt(start)))
  298               start++;
  299   
  300           int end = length;
  301           while(end>start && WhiteSpaceProcessor.isWhiteSpace(text.charAt(end-1)))
  302               end--;
  303   
  304           if(end==start)
  305               throw new IllegalArgumentException("input is empty");
  306   
  307   
  308           String uri;
  309           String localPart;
  310           String prefix;
  311   
  312           // search ':'
  313           int idx=start+1;    // no point in searching the first char. that's not valid.
  314           while(idx<end && text.charAt(idx)!=':' )
  315               idx++;
  316   
  317           if( idx==end ) {
  318               uri = nsc.getNamespaceURI("");
  319               localPart = text.subSequence(start,end).toString();
  320               prefix = "";
  321           } else {
  322               // Prefix exists, check everything
  323               prefix = text.subSequence(start,idx).toString();
  324               localPart = text.subSequence(idx+1,end).toString();
  325               uri = nsc.getNamespaceURI(prefix);
  326               // uri can never be null according to javadoc,
  327               // but some users reported that there are implementations that return null.
  328               if(uri==null || uri.length()==0) // crap. the NamespaceContext interface is broken.
  329                   // error: unbound prefix
  330                   throw new IllegalArgumentException("prefix "+prefix+" is not bound to a namespace");
  331           }
  332   
  333           return new QName(uri,localPart,prefix);
  334       }
  335   
  336       public Calendar parseDateTime(String lexicalXSDDateTime) {
  337           return _parseDateTime(lexicalXSDDateTime);
  338       }
  339   
  340       public static GregorianCalendar _parseDateTime(CharSequence s) {
  341           String val = WhiteSpaceProcessor.trim(s).toString();
  342           return datatypeFactory.newXMLGregorianCalendar(val).toGregorianCalendar();
  343       }
  344   
  345       public String printDateTime(Calendar val) {
  346           return _printDateTime(val);
  347       }
  348   
  349       public static String _printDateTime(Calendar val) {
  350           return CalendarFormatter.doFormat("%Y-%M-%DT%h:%m:%s%z",val);
  351       }
  352   
  353       public byte[] parseBase64Binary(String lexicalXSDBase64Binary) {
  354           return _parseBase64Binary(lexicalXSDBase64Binary);
  355       }
  356   
  357   
  358       public byte[] parseHexBinary(String s) {
  359           final int len = s.length();
  360   
  361           // "111" is not a valid hex encoding.
  362           if( len%2 != 0 )
  363               throw new IllegalArgumentException("hexBinary needs to be even-length: "+s);
  364   
  365           byte[] out = new byte[len/2];
  366   
  367           for( int i=0; i<len; i+=2 ) {
  368               int h = hexToBin(s.charAt(i  ));
  369               int l = hexToBin(s.charAt(i+1));
  370               if( h==-1 || l==-1 )
  371                   throw new IllegalArgumentException("contains illegal character for hexBinary: "+s);
  372   
  373               out[i/2] = (byte)(h*16+l);
  374           }
  375   
  376           return out;
  377       }
  378   
  379       private static int hexToBin( char ch ) {
  380           if( '0'<=ch && ch<='9' )    return ch-'0';
  381           if( 'A'<=ch && ch<='F' )    return ch-'A'+10;
  382           if( 'a'<=ch && ch<='f' )    return ch-'a'+10;
  383           return -1;
  384       }
  385   
  386       private static final char[] hexCode = "0123456789ABCDEF".toCharArray();
  387   
  388       public String printHexBinary(byte[] data) {
  389           StringBuilder r = new StringBuilder(data.length*2);
  390           for ( byte b : data) {
  391               r.append(hexCode[(b >> 4) & 0xF]);
  392               r.append(hexCode[(b & 0xF)]);
  393           }
  394           return r.toString();
  395       }
  396   
  397   
  398       public long parseUnsignedInt(String lexicalXSDUnsignedInt) {
  399           return _parseLong(lexicalXSDUnsignedInt);
  400       }
  401   
  402       public String printUnsignedInt(long val) {
  403           return _printLong(val);
  404       }
  405   
  406       public int parseUnsignedShort(String lexicalXSDUnsignedShort) {
  407           return _parseInt(lexicalXSDUnsignedShort);
  408       }
  409   
  410       public Calendar parseTime(String lexicalXSDTime) {
  411           return datatypeFactory.newXMLGregorianCalendar(lexicalXSDTime).toGregorianCalendar();
  412       }
  413   
  414       public String printTime(Calendar val) {
  415           return CalendarFormatter.doFormat("%h:%m:%s%z",val);
  416       }
  417   
  418       public Calendar parseDate(String lexicalXSDDate) {
  419           return datatypeFactory.newXMLGregorianCalendar(lexicalXSDDate).toGregorianCalendar();
  420       }
  421   
  422       public String printDate(Calendar val) {
  423   
  424           return CalendarFormatter.doFormat((new StringBuilder("%Y-%M-%D").append("%z")).toString(),val);
  425       }
  426   
  427       public String parseAnySimpleType(String lexicalXSDAnySimpleType) {
  428           return lexicalXSDAnySimpleType;
  429   //        return (String)SimpleURType.theInstance._createValue( lexicalXSDAnySimpleType, null );
  430       }
  431   
  432       public String printString(String val) {
  433   //        return StringType.theInstance.convertToLexicalValue( val, null );
  434           return val;
  435       }
  436   
  437   
  438       public String printInt(int val) {
  439           return _printInt(val);
  440       }
  441   
  442       public static String _printInt(int val) {
  443           return String.valueOf(val);
  444       }
  445   
  446       public String printLong(long val) {
  447           return _printLong(val);
  448       }
  449   
  450       public static String _printLong(long val) {
  451           return String.valueOf(val);
  452       }
  453   
  454       public String printDecimal(BigDecimal val) {
  455           return _printDecimal(val);
  456       }
  457   
  458       public static String _printDecimal(BigDecimal val) {
  459           return val.toPlainString();
  460       }
  461   
  462       public String printDouble(double v) {
  463           return _printDouble(v);
  464       }
  465   
  466       public static String _printDouble(double v) {
  467           if(Double.isNaN(v))                  return "NaN";
  468           if( v==Double.POSITIVE_INFINITY )    return "INF";
  469           if( v==Double.NEGATIVE_INFINITY )    return "-INF";
  470           return String.valueOf(v);
  471       }
  472   
  473       public String printQName(QName val, NamespaceContext nsc) {
  474           return _printQName(val,nsc);
  475       }
  476   
  477       public static String _printQName(QName val, NamespaceContext nsc) {
  478           // Double-check
  479           String qname;
  480           String prefix = nsc.getPrefix( val.getNamespaceURI() );
  481           String localPart = val.getLocalPart();
  482   
  483           if( prefix == null || prefix.length()==0 ) { // be defensive
  484               qname = localPart;
  485           } else {
  486               qname = prefix + ':' + localPart;
  487           }
  488   
  489           return qname;
  490       }
  491   
  492       public String printBase64Binary(byte[] val) {
  493           return _printBase64Binary(val);
  494       }
  495   
  496       public String printUnsignedShort(int val) {
  497           return String.valueOf(val);
  498       }
  499   
  500       public String printAnySimpleType(String val) {
  501           return val;
  502       }
  503   
  504   
  505       /**
  506        * Just return the string passed as a parameter but
  507        * installs an instance of this class as the DatatypeConverter
  508        * implementation. Used from static fixed value initializers.
  509        */
  510       public static String installHook( String s ) {
  511           DatatypeConverter.setDatatypeConverter(theInstance);
  512           return s;
  513       }
  514   
  515   
  516   
  517   
  518   // base64 decoder
  519   //====================================
  520   
  521       private static final byte[] decodeMap = initDecodeMap();
  522       private static final byte PADDING = 127;
  523   
  524       private static byte[] initDecodeMap() {
  525           byte[] map = new byte[128];
  526           int i;
  527           for( i=0; i<128; i++ )        map[i] = -1;
  528   
  529           for( i='A'; i<='Z'; i++ )    map[i] = (byte)(i-'A');
  530           for( i='a'; i<='z'; i++ )    map[i] = (byte)(i-'a'+26);
  531           for( i='0'; i<='9'; i++ )    map[i] = (byte)(i-'0'+52);
  532           map['+'] = 62;
  533           map['/'] = 63;
  534           map['='] = PADDING;
  535   
  536           return map;
  537       }
  538   
  539       /**
  540        * computes the length of binary data speculatively.
  541        *
  542        * <p>
  543        * Our requirement is to create byte[] of the exact length to store the binary data.
  544        * If we do this in a straight-forward way, it takes two passes over the data.
  545        * Experiments show that this is a non-trivial overhead (35% or so is spent on
  546        * the first pass in calculating the length.)
  547        *
  548        * <p>
  549        * So the approach here is that we compute the length speculatively, without looking
  550        * at the whole contents. The obtained speculative value is never less than the
  551        * actual length of the binary data, but it may be bigger. So if the speculation
  552        * goes wrong, we'll pay the cost of reallocation and buffer copying.
  553        *
  554        * <p>
  555        * If the base64 text is tightly packed with no indentation nor illegal char
  556        * (like what most web services produce), then the speculation of this method
  557        * will be correct, so we get the performance benefit.
  558        */
  559       private static int guessLength( String text ) {
  560           final int len = text.length();
  561   
  562           // compute the tail '=' chars
  563           int j=len-1;
  564           for(; j>=0; j-- ) {
  565               byte code = decodeMap[text.charAt(j)];
  566               if(code==PADDING)
  567                   continue;
  568               if(code==-1)
  569                   // most likely this base64 text is indented. go with the upper bound
  570                   return text.length()/4*3;
  571               break;
  572           }
  573   
  574           j++;    // text.charAt(j) is now at some base64 char, so +1 to make it the size
  575           int padSize = len-j;
  576           if(padSize >2) // something is wrong with base64. be safe and go with the upper bound
  577               return text.length()/4*3;
  578   
  579           // so far this base64 looks like it's unindented tightly packed base64.
  580           // take a chance and create an array with the expected size
  581           return text.length()/4*3-padSize;
  582       }
  583   
  584       /**
  585        * @param text
  586        *      base64Binary data is likely to be long, and decoding requires
  587        *      each character to be accessed twice (once for counting length, another
  588        *      for decoding.)
  589        *
  590        *      A benchmark showed that taking {@link String} is faster, presumably
  591        *      because JIT can inline a lot of string access (with data of 1K chars, it was twice as fast)
  592        */
  593       public static byte[] _parseBase64Binary(String text) {
  594           final int buflen = guessLength(text);
  595           final byte[] out = new byte[buflen];
  596           int o=0;
  597   
  598           final int len = text.length();
  599           int i;
  600   
  601           final byte[] quadruplet = new byte[4];
  602           int q=0;
  603   
  604           // convert each quadruplet to three bytes.
  605           for( i=0; i<len; i++ ) {
  606               char ch = text.charAt(i);
  607               byte v = decodeMap[ch];
  608   
  609               if( v!=-1 )
  610                   quadruplet[q++] = v;
  611   
  612               if(q==4) {
  613                   // quadruplet is now filled.
  614                   out[o++] = (byte)((quadruplet[0]<<2)|(quadruplet[1]>>4));
  615                   if( quadruplet[2]!=PADDING )
  616                       out[o++] = (byte)((quadruplet[1]<<4)|(quadruplet[2]>>2));
  617                   if( quadruplet[3]!=PADDING )
  618                       out[o++] = (byte)((quadruplet[2]<<6)|(quadruplet[3]));
  619                   q=0;
  620               }
  621           }
  622   
  623           if(buflen==o) // speculation worked out to be OK
  624               return out;
  625   
  626           // we overestimated, so need to create a new buffer
  627           byte[] nb = new byte[o];
  628           System.arraycopy(out,0,nb,0,o);
  629           return nb;
  630       }
  631   
  632       private static final char[] encodeMap = initEncodeMap();
  633   
  634       private static char[] initEncodeMap() {
  635           char[] map = new char[64];
  636           int i;
  637           for( i= 0; i<26; i++ )        map[i] = (char)('A'+i);
  638           for( i=26; i<52; i++ )        map[i] = (char)('a'+(i-26));
  639           for( i=52; i<62; i++ )        map[i] = (char)('0'+(i-52));
  640           map[62] = '+';
  641           map[63] = '/';
  642   
  643           return map;
  644       }
  645   
  646       public static char encode( int i ) {
  647           return encodeMap[i&0x3F];
  648       }
  649   
  650       public static byte encodeByte( int i ) {
  651           return (byte)encodeMap[i&0x3F];
  652       }
  653   
  654       public static String _printBase64Binary(byte[] input) {
  655           return _printBase64Binary(input, 0, input.length);
  656       }
  657       public static String _printBase64Binary(byte[] input, int offset, int len) {
  658           char[] buf = new char[((len+2)/3)*4];
  659           int ptr = _printBase64Binary(input,offset,len,buf,0);
  660           assert ptr==buf.length;
  661           return new String(buf);
  662       }
  663   
  664       /**
  665        * Encodes a byte array into a char array by doing base64 encoding.
  666        *
  667        * The caller must supply a big enough buffer.
  668        *
  669        * @return
  670        *      the value of {@code ptr+((len+2)/3)*4}, which is the new offset
  671        *      in the output buffer where the further bytes should be placed.
  672        */
  673       public static int _printBase64Binary(byte[] input, int offset, int len, char[] buf, int ptr) {
  674           for( int i=offset; i<len; i+=3 ) {
  675               switch( len-i ) {
  676               case 1:
  677                   buf[ptr++] = encode(input[i]>>2);
  678                   buf[ptr++] = encode(((input[i])&0x3)<<4);
  679                   buf[ptr++] = '=';
  680                   buf[ptr++] = '=';
  681                   break;
  682               case 2:
  683                   buf[ptr++] = encode(input[i]>>2);
  684                   buf[ptr++] = encode(
  685                               ((input[i]&0x3)<<4) |
  686                               ((input[i+1]>>4)&0xF));
  687                   buf[ptr++] = encode((input[i+1]&0xF)<<2);
  688                   buf[ptr++] = '=';
  689                   break;
  690               default:
  691                   buf[ptr++] = encode(input[i]>>2);
  692                   buf[ptr++] = encode(
  693                               ((input[i]&0x3)<<4) |
  694                               ((input[i+1]>>4)&0xF));
  695                   buf[ptr++] = encode(
  696                               ((input[i+1]&0xF)<<2)|
  697                               ((input[i+2]>>6)&0x3));
  698                   buf[ptr++] = encode(input[i+2]&0x3F);
  699                   break;
  700               }
  701           }
  702           return ptr;
  703       }
  704   
  705       /**
  706        * Encodes a byte array into another byte array by first doing base64 encoding
  707        * then encoding the result in ASCII.
  708        *
  709        * The caller must supply a big enough buffer.
  710        *
  711        * @return
  712        *      the value of {@code ptr+((len+2)/3)*4}, which is the new offset
  713        *      in the output buffer where the further bytes should be placed.
  714        */
  715       public static int _printBase64Binary(byte[] input, int offset, int len, byte[] out, int ptr) {
  716           byte[] buf = out;
  717           int max = len+offset;
  718           for( int i=offset; i<max; i+=3 ) {
  719               switch( max-i ) {
  720               case 1:
  721                   buf[ptr++] = encodeByte(input[i]>>2);
  722                   buf[ptr++] = encodeByte(((input[i])&0x3)<<4);
  723                   buf[ptr++] = '=';
  724                   buf[ptr++] = '=';
  725                   break;
  726               case 2:
  727                   buf[ptr++] = encodeByte(input[i]>>2);
  728                   buf[ptr++] = encodeByte(
  729                               ((input[i]&0x3)<<4) |
  730                               ((input[i+1]>>4)&0xF));
  731                   buf[ptr++] = encodeByte((input[i+1]&0xF)<<2);
  732                   buf[ptr++] = '=';
  733                   break;
  734               default:
  735                   buf[ptr++] = encodeByte(input[i]>>2);
  736                   buf[ptr++] = encodeByte(
  737                               ((input[i]&0x3)<<4) |
  738                               ((input[i+1]>>4)&0xF));
  739                   buf[ptr++] = encodeByte(
  740                               ((input[i+1]&0xF)<<2)|
  741                               ((input[i+2]>>6)&0x3));
  742                   buf[ptr++] = encodeByte(input[i+2]&0x3F);
  743                   break;
  744               }
  745           }
  746   
  747           return ptr;
  748       }
  749   
  750       private static CharSequence removeOptionalPlus(CharSequence s) {
  751           int len = s.length();
  752   
  753           if(len<=1 || s.charAt(0)!='+')    return s;
  754   
  755           s = s.subSequence(1,len);
  756           char ch = s.charAt(0);
  757           if('0'<=ch && ch<='9')    return s;
  758           if('.'==ch )    return s;
  759   
  760           throw new NumberFormatException();
  761       }
  762   
  763       private static boolean isDigitOrPeriodOrSign( char ch ) {
  764           if( '0'<=ch && ch<='9' )    return true;
  765           if( ch=='+' || ch=='-' || ch=='.' )    return true;
  766           return false;
  767       }
  768   
  769       private static final DatatypeFactory datatypeFactory;
  770   
  771       static {
  772           try {
  773               datatypeFactory = DatatypeFactory.newInstance();
  774           } catch (DatatypeConfigurationException e) {
  775               throw new Error(e);
  776           }
  777       }
  778   
  779   
  780       private static final class CalendarFormatter {
  781           public static String doFormat( String format, Calendar cal ) throws IllegalArgumentException {
  782               int fidx = 0;
  783               int flen = format.length();
  784               StringBuilder buf = new StringBuilder();
  785   
  786               while(fidx<flen) {
  787                   char fch = format.charAt(fidx++);
  788   
  789                   if(fch!='%') {  // not a meta character
  790                       buf.append(fch);
  791                       continue;
  792                   }
  793   
  794                   // seen meta character. we don't do error check against the format
  795                   switch (format.charAt(fidx++)) {
  796                   case 'Y' : // year
  797                       formatYear(cal, buf);
  798                       break;
  799   
  800                   case 'M' : // month
  801                       formatMonth(cal, buf);
  802                       break;
  803   
  804                   case 'D' : // days
  805                       formatDays(cal, buf);
  806                       break;
  807   
  808                   case 'h' : // hours
  809                       formatHours(cal, buf);
  810                       break;
  811   
  812                   case 'm' : // minutes
  813                       formatMinutes(cal, buf);
  814                       break;
  815   
  816                   case 's' : // parse seconds.
  817                       formatSeconds(cal, buf);
  818                       break;
  819   
  820                   case 'z' : // time zone
  821                       formatTimeZone(cal,buf);
  822                       break;
  823   
  824                   default :
  825                       // illegal meta character. impossible.
  826                       throw new InternalError();
  827                   }
  828               }
  829   
  830               return buf.toString();
  831           }
  832   
  833   
  834           private static void formatYear(Calendar cal, StringBuilder buf) {
  835               int year = cal.get(Calendar.YEAR);
  836   
  837               String s;
  838               if (year <= 0) // negative value
  839                   s = Integer.toString(1 - year);
  840               else // positive value
  841                   s = Integer.toString(year);
  842   
  843               while (s.length() < 4)
  844                   s = '0' + s;
  845               if (year <= 0)
  846                   s = '-' + s;
  847   
  848               buf.append(s);
  849           }
  850   
  851           private static void formatMonth(Calendar cal, StringBuilder buf) {
  852               formatTwoDigits(cal.get(Calendar.MONTH)+1,buf);
  853           }
  854   
  855           private static void formatDays(Calendar cal, StringBuilder buf) {
  856               formatTwoDigits(cal.get(Calendar.DAY_OF_MONTH),buf);
  857           }
  858   
  859           private static void formatHours(Calendar cal, StringBuilder buf) {
  860               formatTwoDigits(cal.get(Calendar.HOUR_OF_DAY),buf);
  861           }
  862   
  863           private static void formatMinutes(Calendar cal, StringBuilder buf) {
  864               formatTwoDigits(cal.get(Calendar.MINUTE),buf);
  865           }
  866   
  867           private static void formatSeconds(Calendar cal, StringBuilder buf) {
  868               formatTwoDigits(cal.get(Calendar.SECOND),buf);
  869               if (cal.isSet(Calendar.MILLISECOND)) { // milliseconds
  870                   int n = cal.get(Calendar.MILLISECOND);
  871                   if(n!=0) {
  872                       String ms = Integer.toString(n);
  873                       while (ms.length() < 3)
  874                           ms = '0' + ms; // left 0 paddings.
  875   
  876                       buf.append('.');
  877                       buf.append(ms);
  878                   }
  879               }
  880           }
  881   
  882           /** formats time zone specifier. */
  883           private static void formatTimeZone(Calendar cal,StringBuilder buf) {
  884               TimeZone tz = cal.getTimeZone();
  885   
  886               if (tz == null)      return;
  887   
  888               // otherwise print out normally.
  889               int offset = tz.getOffset(cal.getTime().getTime());
  890   
  891               if(offset==0) {
  892                   buf.append('Z');
  893                   return;
  894               }
  895   
  896               if (offset >= 0)
  897                   buf.append('+');
  898               else {
  899                   buf.append('-');
  900                   offset *= -1;
  901               }
  902   
  903               offset /= 60 * 1000; // offset is in milli-seconds
  904   
  905               formatTwoDigits(offset / 60, buf);
  906               buf.append(':');
  907               formatTwoDigits(offset % 60, buf);
  908           }
  909   
  910           /** formats Integer into two-character-wide string. */
  911           private static void formatTwoDigits(int n,StringBuilder buf) {
  912               // n is always non-negative.
  913               if (n < 10) buf.append('0');
  914               buf.append(n);
  915           }
  916       }
  917   }

Save This Page
Home » Open-JDK-6.b17-src » com.sun.xml.internal » bind » [javadoc | source]