src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/staxex/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 408
b0610cd08440
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 2012, 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.org.jvnet.staxex;
    28 import javax.activation.DataHandler;
    29 import javax.activation.DataSource;
    30 import java.io.ByteArrayInputStream;
    31 import java.io.ByteArrayOutputStream;
    32 import java.io.File;
    33 import java.io.FileOutputStream;
    34 import java.io.IOException;
    35 import java.io.InputStream;
    36 import java.io.OutputStream;
    37 import javax.xml.stream.XMLStreamException;
    38 import javax.xml.stream.XMLStreamWriter;
    39 import java.util.logging.Level;
    40 import java.util.logging.Logger;
    42 // for testing method
    43 //import com.sun.xml.internal.stream.writers.XMLStreamWriterImpl;
    44 //import java.io.FileNotFoundException;
    45 //import java.io.FileWriter;
    46 //import javax.activation.FileDataSource;
    48 /**
    49  * Binary data represented as base64-encoded string
    50  * in XML.
    51  *
    52  * <p>
    53  * Used in conjunction with {@link XMLStreamReaderEx}
    54  * and {@link XMLStreamWriterEx}.
    55  *
    56  * @author Kohsuke Kawaguchi, Martin Grebac
    57  */
    58 public class Base64Data implements CharSequence, Cloneable {
    60     // either dataHandler or (data,dataLen,mimeType?) must be present
    61     // (note that having both is allowed)
    63     private DataHandler dataHandler;
    64     private byte[] data;
    66     /**
    67      * Length of the valid data in {@link #data}.
    68      */
    69     private int dataLen;
    70     /**
    71      * True if {@link #data} can be cloned by reference
    72      * if Base64Data instance is cloned.
    73      */
    74     private boolean dataCloneByRef;
    75     /**
    76      * Optional MIME type of {@link #data}.
    77      *
    78      * Unused when {@link #dataHandler} is set.
    79      * Use {@link DataHandler#getContentType()} in that case.
    80      */
    81     private String mimeType;
    83     /**
    84      * Default constructor
    85      */
    86     public Base64Data() {
    87     }
    89     private static final Logger logger = Logger.getLogger(Base64Data.class.getName());
    91     /**
    92      * Clone constructor
    93      * @param that needs to be cloned
    94      */
    95     public Base64Data(Base64Data that) {
    96         that.get();
    97         if (that.dataCloneByRef) {
    98             this.data = that.data;
    99         } else {
   100             this.data = new byte[that.dataLen];
   101             System.arraycopy(that.data, 0, this.data, 0, that.dataLen);
   102         }
   104         this.dataCloneByRef = true;
   105         this.dataLen = that.dataLen;
   106         this.dataHandler = null;
   107         this.mimeType = that.mimeType;
   108     }
   110     /**
   111      * Fills in the data object by a portion of the byte[].
   112      *
   113      * @param data actual data
   114      * @param len
   115      *      data[0] to data[len-1] are treated as the data.
   116      * @param mimeType MIME type
   117      * @param cloneByRef
   118      *      true if data[] can be cloned by reference
   119      */
   120     public void set(byte[] data, int len, String mimeType, boolean cloneByRef) {
   121         this.data = data;
   122         this.dataLen = len;
   123         this.dataCloneByRef = cloneByRef;
   124         this.dataHandler = null;
   125         this.mimeType = mimeType;
   126     }
   128     /**
   129      * Fills in the data object by a portion of the byte[].
   130      *
   131      * @param data actual data bytes
   132      * @param len
   133      *      data[0] to data[len-1] are treated as the data.
   134      * @param mimeType MIME type
   135      */
   136     public void set(byte[] data, int len, String mimeType) {
   137         set(data,len,mimeType,false);
   138     }
   140     /**
   141      * Fills in the data object by the byte[] of the exact length.
   142      *
   143      * @param data
   144      *      this buffer may be owned directly by the unmarshaleld JAXB object.
   145      * @param mimeType MIME type
   146      */
   147     public void set(byte[] data,String mimeType) {
   148         set(data,data.length,mimeType,false);
   149     }
   151     /**
   152      * Fills in the data object by a {@link DataHandler}.
   153      *
   154      * @param data DataHandler for the data
   155      */
   156     public void set(DataHandler data) {
   157         assert data!=null;
   158         this.dataHandler = data;
   159         this.data = null;
   160     }
   162     /**
   163      * Gets the raw data. If the returned DataHandler is {@link StreamingDataHandler},
   164      * callees may need to downcast to take advantage of its capabilities.
   165      *
   166      * @see StreamingDataHandler
   167      * @return DataHandler for the data
   168      */
   169     public DataHandler getDataHandler() {
   170         if(dataHandler==null){
   171             dataHandler = new Base64StreamingDataHandler(new Base64DataSource());
   172         } else if (!(dataHandler instanceof StreamingDataHandler)) {
   173             dataHandler = new FilterDataHandler(dataHandler);
   174         }
   175         return dataHandler;
   176     }
   178     private final class Base64DataSource implements DataSource {
   179         public String getContentType() {
   180             return getMimeType();
   181         }
   183         public InputStream getInputStream() {
   184             return new ByteArrayInputStream(data,0,dataLen);
   185         }
   187         public String getName() {
   188             return null;
   189         }
   191         public OutputStream getOutputStream() {
   192             throw new UnsupportedOperationException();
   193         }
   195     }
   197     private final class Base64StreamingDataHandler extends StreamingDataHandler {
   199         Base64StreamingDataHandler(DataSource source) {
   200             super(source);
   201         }
   203         public InputStream readOnce() throws IOException {
   204             return getDataSource().getInputStream();
   205         }
   207         public void moveTo(File dst) throws IOException {
   208             FileOutputStream fout = new FileOutputStream(dst);
   209             try {
   210                 fout.write(data, 0, dataLen);
   211             } finally {
   212                 fout.close();
   213             }
   214         }
   216         public void close() throws IOException {
   217             // nothing to do
   218         }
   219     }
   221     private static final class FilterDataHandler extends StreamingDataHandler {
   223         FilterDataHandler(DataHandler dh) {
   224             super(dh.getDataSource());
   225         }
   227         public InputStream readOnce() throws IOException {
   228             return getDataSource().getInputStream();
   229         }
   231         public void moveTo(File dst) throws IOException {
   232             byte[] buf = new byte[8192];
   233             InputStream in = null;
   234             OutputStream out = null;
   235             try {
   236                 in = getDataSource().getInputStream();
   237                 out = new FileOutputStream(dst);
   238                 while (true) {
   239                     int amountRead = in.read(buf);
   240                     if (amountRead == -1) {
   241                         break;
   242                     }
   243                     out.write(buf, 0, amountRead);
   244                 }
   245             } finally {
   246                 if (in != null) {
   247                     try {
   248                         in.close();
   249                     } catch(IOException ioe) {
   250                         // nothing to do
   251                     }
   252                 }
   253                 if (out != null) {
   254                     try {
   255                         out.close();
   256                     } catch(IOException ioe) {
   257                         // nothing to do
   258                     }
   259                 }
   260             }
   261         }
   263         public void close() throws IOException {
   264             // nothing to do
   265         }
   266     }
   268     /**
   269      * Gets the byte[] of the exact length.
   270      *
   271      * @return byte[] for data
   272      */
   273     public byte[] getExact() {
   274         get();
   275         if(dataLen!=data.length) {
   276             byte[] buf = new byte[dataLen];
   277             System.arraycopy(data,0,buf,0,dataLen);
   278             data = buf;
   279         }
   280         return data;
   281     }
   283     /**
   284      * Gets the data as an {@link InputStream}.
   285      *
   286      * @return data as InputStream
   287      * @throws IOException if i/o error occurs
   288      */
   289     public InputStream getInputStream() throws IOException {
   290         if(dataHandler!=null) {
   291             return dataHandler.getInputStream();
   292         } else {
   293             return new ByteArrayInputStream(data,0,dataLen);
   294         }
   295     }
   297     /**
   298      * Returns false if this object only has {@link DataHandler} and therefore
   299      * {@link #get()} operation is likely going to be expensive.
   300      *
   301      * @return false if it has only DataHandler
   302      */
   303     public boolean hasData() {
   304         return data!=null;
   305     }
   307     /**
   308      * Gets the raw data. The size of the byte array maybe larger than the actual length.
   309      *
   310      * @return data as byte[], the array may be larger
   311      */
   312     public byte[] get() {
   313         if(data==null) {
   314             try {
   315                 ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
   316                 InputStream is = dataHandler.getDataSource().getInputStream();
   317                 baos.readFrom(is);
   318                 is.close();
   319                 data = baos.getBuffer();
   320                 dataLen = baos.size();
   321                 dataCloneByRef = true;
   322             } catch (IOException e) {
   323                 // TODO: report the error to the unmarshaller
   324                 dataLen = 0;    // recover by assuming length-0 data
   325             }
   326         }
   327         return data;
   328     }
   330     /**
   331      * Gets the length of the binary data counted in bytes.
   332      *
   333      * Note that if this object encapsulates {@link DataHandler},
   334      * this method would have to read the whole thing into {@code byte[]}
   335      * just to count the length, because {@link DataHandler}
   336      * doesn't easily expose the length.
   337      *
   338      * @return no of bytes
   339      */
   340     public int getDataLen() {
   341         get();
   342         return dataLen;
   343     }
   345     public String getMimeType() {
   346         if (mimeType==null) {
   347             return "application/octet-stream";
   348         }
   349         return mimeType;
   350     }
   352     /**
   353      * Gets the number of characters needed to represent
   354      * this binary data in the base64 encoding.
   355      */
   356     public int length() {
   357         // for each 3 bytes you use 4 chars
   358         // if the remainder is 1 or 2 there will be 4 more
   359         get();  // fill in the buffer if necessary
   360         return ((dataLen+2)/3)*4;
   361     }
   363     /**
   364      * Encode this binary data in the base64 encoding
   365      * and returns the character at the specified position.
   366      */
   367     public char charAt(int index) {
   368         // we assume that the length() method is called before this method
   369         // (otherwise how would the caller know that the index is valid?)
   370         // so we assume that the byte[] is already populated
   372         int offset = index%4;
   373         int base = (index/4)*3;
   375         byte b1,b2;
   377         switch(offset) {
   378         case 0:
   379             return Base64Encoder.encode(data[base]>>2);
   380         case 1:
   381             if (base+1<dataLen) {
   382                 b1 = data[base+1];
   383             } else {
   384                 b1 = 0;
   385             }
   386             return Base64Encoder.encode(
   387                         ((data[base]&0x3)<<4) |
   388                         ((b1>>4)&0xF));
   389         case 2:
   390             if (base+1<dataLen) {
   391                 b1 = data[base+1];
   392                 if (base+2<dataLen) {
   393                     b2 = data[base+2];
   394                 } else {
   395                     b2 = 0;
   396                 }
   398                 return Base64Encoder.encode(
   399                             ((b1&0xF)<<2)|
   400                             ((b2>>6)&0x3));
   401             } else {
   402                 return '=';
   403             }
   404         case 3:
   405             if(base+2<dataLen) {
   406                 return Base64Encoder.encode(data[base+2]&0x3F);
   407             } else {
   408                 return '=';
   409             }
   410         }
   412         throw new IllegalStateException();
   413     }
   415     /**
   416      * Internally this is only used to split a text to a list,
   417      * which doesn't happen that much for base64.
   418      * So this method should be smaller than faster.
   419      */
   420     public CharSequence subSequence(int start, int end) {
   421         StringBuilder buf = new StringBuilder();
   422         get();  // fill in the buffer if we haven't done so
   423         for (int i=start; i<end; i++ ) {
   424             buf.append(charAt(i));
   425         }
   426         return buf;
   427     }
   429     /**
   430      * Returns the base64 encoded string of this data.
   431      */
   432     @Override
   433     public String toString() {
   434         get();  // fill in the buffer
   435         return Base64Encoder.print(data, 0, dataLen);
   436     }
   438     public void writeTo(char[] buf, int start) {
   439         get();
   440         Base64Encoder.print(data, 0, dataLen, buf, start);
   441     }
   443     private static final int CHUNK_SIZE;
   444     static {
   445         int bufSize = 1024;
   446         try {
   447             String bufSizeStr = getProperty("com.sun.xml.internal.org.jvnet.staxex.Base64DataStreamWriteBufferSize");
   448             if (bufSizeStr != null) {
   449                 bufSize = Integer.parseInt(bufSizeStr);
   450             }
   451         } catch (Exception e) {
   452             logger.log(Level.INFO, "Error reading com.sun.xml.internal.org.jvnet.staxex.Base64DataStreamWriteBufferSize property", e);
   453         }
   454         CHUNK_SIZE = bufSize;
   455     }
   457     public void writeTo(XMLStreamWriter output) throws IOException, XMLStreamException {
   458         if (data==null) {
   459             try {
   460                 InputStream is = dataHandler.getDataSource().getInputStream();
   461                 ByteArrayOutputStream outStream = new ByteArrayOutputStream(); // dev-null stream
   462                 Base64EncoderStream encWriter = new Base64EncoderStream(output, outStream);
   463                 int b;
   464                 byte[] buffer = new byte[CHUNK_SIZE];
   465                 while ((b = is.read(buffer)) != -1) {
   466                     encWriter.write(buffer, 0, b);
   467                 }
   468                 outStream.close();
   469                 encWriter.close();
   470             } catch (IOException e) {
   471                 dataLen = 0;    // recover by assuming length-0 data
   472                 throw e;
   473             }
   474         } else {
   475             // the data is already in memory and not streamed
   476             String s = Base64Encoder.print(data, 0, dataLen);
   477             output.writeCharacters(s);
   478         }
   479     }
   481     @Override
   482     public Base64Data clone() {
   483         try {
   484             Base64Data clone = (Base64Data) super.clone();
   485             clone.get();
   486             if (clone.dataCloneByRef) {
   487                 this.data = clone.data;
   488             } else {
   489                 this.data = new byte[clone.dataLen];
   490                 System.arraycopy(clone.data, 0, this.data, 0, clone.dataLen);
   491             }
   493             this.dataCloneByRef = true;
   494             this.dataLen = clone.dataLen;
   495             this.dataHandler = null;
   496             this.mimeType = clone.mimeType;
   497             return clone;
   498         } catch (CloneNotSupportedException ex) {
   499             Logger.getLogger(Base64Data.class.getName()).log(Level.SEVERE, null, ex);
   500             return null;
   501         }
   502     }
   504     static String getProperty(final String propName) {
   505         if (System.getSecurityManager() == null) {
   506             return System.getProperty(propName);
   507         } else {
   508             return (String) java.security.AccessController.doPrivileged(
   509                     new java.security.PrivilegedAction() {
   510                         public java.lang.Object run() {
   511                             return System.getProperty(propName);
   512                         }
   513                     });
   514         }
   515     }
   517 //    public static void main(String[] args) throws FileNotFoundException, IOException, XMLStreamException {
   518 //        Base64Data data = new Base64Data();
   519 //
   520 //        File f = new File("/Users/snajper/work/builds/weblogic/wls1211_dev.zip");
   521 //        FileDataSource fds = new FileDataSource(f);
   522 //        DataHandler dh = new DataHandler(fds);
   523 //        data.set(dh);
   524 //
   525 //        FileWriter fw = new FileWriter(new File("/Users/snajper/Desktop/b.txt"));
   526 //        XMLStreamWriterImpl wi = new XMLStreamWriterImpl(fw, null);
   527 //
   528 //        data.writeTo(wi);
   529 //        wi.flush();fw.flush();
   530 //        //System.out.println("SW: " + sw.toString());
   531 //
   532 //    }
   534 }

mercurial