src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Base64Data.java

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

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

merge

     1 /*
     2  * Copyright (c) 1997, 2011, 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.v2.runtime.unmarshaller;
    28 import java.io.ByteArrayInputStream;
    29 import java.io.IOException;
    30 import java.io.InputStream;
    31 import java.io.OutputStream;
    33 import javax.activation.DataHandler;
    34 import javax.activation.DataSource;
    35 import javax.xml.stream.XMLStreamException;
    37 import javax.xml.stream.XMLStreamWriter;
    39 import com.sun.xml.internal.bind.DatatypeConverterImpl;
    40 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
    41 import com.sun.xml.internal.bind.v2.runtime.output.Pcdata;
    42 import com.sun.xml.internal.bind.v2.runtime.output.UTF8XmlOutput;
    43 import com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx;
    44 import com.sun.istack.internal.Nullable;
    46 /**
    47  * Fed to unmarshaller when the 'text' data is actually
    48  * a virtual image of base64 encoding of the binary data
    49  * transferred on the wire.
    50  *
    51  * Used for the MTOM support.
    52  *
    53  * This object is mutable and the owner of this object can
    54  * reuse it with new data.
    55  *
    56  * Also used by the marshaller to write out the binary data
    57  * that could be possibly attached.
    58  *
    59  * @see XmlVisitor#text(CharSequence)
    60  * @see XMLSerializer#text(Pcdata,String)
    61  *
    62  * @author Kohsuke Kawaguchi, Martin Grebac
    63  */
    64 public final class Base64Data extends Pcdata {
    66     // either dataHandler or (data,dataLen,mimeType?) must be present
    67     private DataHandler dataHandler;
    68     private byte[] data;
    69     /**
    70      * Length of the valid data in {@link #data}.
    71      */
    72     private int dataLen;
    73     /**
    74      * Optional MIME type of {@link #data}.
    75      *
    76      * Unused when {@link #dataHandler} is set.
    77      * Use {@link DataHandler#getContentType()} in that case.
    78      */
    79     private @Nullable
    80     String mimeType;
    82     /**
    83      * Fills in the data object by a portion of the byte[].
    84      *
    85      * @param len
    86      *      data[0] to data[len-1] are treated as the data.
    87      */
    88     public void set(byte[] data, int len, @Nullable String mimeType) {
    89         this.data = data;
    90         this.dataLen = len;
    91         this.dataHandler = null;
    92         this.mimeType = mimeType;
    93     }
    95     /**
    96      * Fills in the data object by the byte[] of the exact length.
    97      *
    98      * @param data
    99      *      this buffer may be owned directly by the unmarshaleld JAXB object.
   100      */
   101     public void set(byte[] data, @Nullable String mimeType) {
   102         set(data, data.length, mimeType);
   103     }
   105     /**
   106      * Fills in the data object by a {@link DataHandler}.
   107      */
   108     public void set(DataHandler data) {
   109         assert data != null;
   110         this.dataHandler = data;
   111         this.data = null;
   112     }
   114     /**
   115      * Gets the raw data.
   116      */
   117     public DataHandler getDataHandler() {
   118         if (dataHandler == null) {
   119             dataHandler = new DataHandler(new DataSource() {
   121                 public String getContentType() {
   122                     return getMimeType();
   123                 }
   125                 public InputStream getInputStream() {
   126                     return new ByteArrayInputStream(data, 0, dataLen);
   127                 }
   129                 public String getName() {
   130                     return null;
   131                 }
   133                 public OutputStream getOutputStream() {
   134                     throw new UnsupportedOperationException();
   135                 }
   136             });
   137         }
   139         return dataHandler;
   140     }
   142     /**
   143      * Gets the byte[] of the exact length.
   144      */
   145     public byte[] getExact() {
   146         get();
   147         if (dataLen != data.length) {
   148             byte[] buf = new byte[dataLen];
   149             System.arraycopy(data, 0, buf, 0, dataLen);
   150             data = buf;
   151         }
   152         return data;
   153     }
   155     /**
   156      * Gets the data as an {@link InputStream}.
   157      */
   158     public InputStream getInputStream() throws IOException {
   159         if (dataHandler != null) {
   160             return dataHandler.getInputStream();
   161         } else {
   162             return new ByteArrayInputStream(data, 0, dataLen);
   163         }
   164     }
   166     /**
   167      * Returns false if this object only has {@link DataHandler} and therefore
   168      * {@link #get()} operation is likely going to be expensive.
   169      */
   170     public boolean hasData() {
   171         return data != null;
   172     }
   174     /**
   175      * Gets the raw data. The size of the byte array maybe larger than the actual length.
   176      */
   177     public byte[] get() {
   178         if (data == null) {
   179             try {
   180                 ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
   181                 InputStream is = dataHandler.getDataSource().getInputStream();
   182                 baos.readFrom(is);
   183                 is.close();
   184                 data = baos.getBuffer();
   185                 dataLen = baos.size();
   186             } catch (IOException e) {
   187                 // TODO: report the error to the unmarshaller
   188                 dataLen = 0;    // recover by assuming length-0 data
   189             }
   190         }
   191         return data;
   192     }
   194     public int getDataLen() {
   195         return dataLen;
   196     }
   198     public String getMimeType() {
   199         if (mimeType == null) {
   200             return "application/octet-stream";
   201         }
   202         return mimeType;
   203     }
   205     /**
   206      * Gets the number of characters needed to represent
   207      * this binary data in the base64 encoding.
   208      */
   209     public int length() {
   210         // for each 3 bytes you use 4 chars
   211         // if the remainder is 1 or 2 there will be 4 more
   212         get();  // fill in the buffer if necessary
   213         return ((dataLen + 2) / 3) * 4;
   214     }
   216     /**
   217      * Encode this binary data in the base64 encoding
   218      * and returns the character at the specified position.
   219      */
   220     public char charAt(int index) {
   221         // we assume that the length() method is called before this method
   222         // (otherwise how would the caller know that the index is valid?)
   223         // so we assume that the byte[] is already populated
   225         int offset = index % 4;
   226         int base = (index / 4) * 3;
   228         byte b1, b2;
   230         switch (offset) {
   231             case 0:
   232                 return DatatypeConverterImpl.encode(data[base] >> 2);
   233             case 1:
   234                 if (base + 1 < dataLen) {
   235                     b1 = data[base + 1];
   236                 } else {
   237                     b1 = 0;
   238                 }
   239                 return DatatypeConverterImpl.encode(
   240                         ((data[base] & 0x3) << 4)
   241                         | ((b1 >> 4) & 0xF));
   242             case 2:
   243                 if (base + 1 < dataLen) {
   244                     b1 = data[base + 1];
   245                     if (base + 2 < dataLen) {
   246                         b2 = data[base + 2];
   247                     } else {
   248                         b2 = 0;
   249                     }
   251                     return DatatypeConverterImpl.encode(
   252                             ((b1 & 0xF) << 2)
   253                             | ((b2 >> 6) & 0x3));
   254                 } else {
   255                     return '=';
   256                 }
   257             case 3:
   258                 if (base + 2 < dataLen) {
   259                     return DatatypeConverterImpl.encode(data[base + 2] & 0x3F);
   260                 } else {
   261                     return '=';
   262                 }
   263         }
   265         throw new IllegalStateException();
   266     }
   268     /**
   269      * Internally this is only used to split a text to a list,
   270      * which doesn't happen that much for base64.
   271      * So this method should be smaller than faster.
   272      */
   273     public CharSequence subSequence(int start, int end) {
   274         StringBuilder buf = new StringBuilder();
   275         get();  // fill in the buffer if we haven't done so
   276         for (int i = start; i < end; i++) {
   277             buf.append(charAt(i));
   278         }
   279         return buf;
   280     }
   282     /**
   283      * Returns the base64 encoded string of this data.
   284      */
   285     public String toString() {
   286         get();  // fill in the buffer
   287         return DatatypeConverterImpl._printBase64Binary(data, 0, dataLen);
   288     }
   290     @Override
   291     public void writeTo(char[] buf, int start) {
   292         get();
   293         DatatypeConverterImpl._printBase64Binary(data, 0, dataLen, buf, start);
   294     }
   296     public void writeTo(UTF8XmlOutput output) throws IOException {
   297         // TODO: this is inefficient if the data source is note byte[] but DataHandler
   298         get();
   299         output.text(data, dataLen);
   300     }
   302     public void writeTo(XMLStreamWriter output) throws IOException, XMLStreamException {
   303         get();
   304         DatatypeConverterImpl._printBase64Binary(data, 0, dataLen, output);
   305     }
   307 }

mercurial