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

Sun, 31 Aug 2014 16:14:36 +0400

author
aefimov
date
Sun, 31 Aug 2014 16:14:36 +0400
changeset 650
121e938cb9c3
parent 0
373ffda63c9a
permissions
-rw-r--r--

8036981: JAXB not preserving formatting for xsd:any Mixed content
Reviewed-by: lancea, mkos

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.xml.internal.bind.v2.runtime.unmarshaller;
aoqi@0 27
aoqi@0 28 import java.io.ByteArrayInputStream;
aoqi@0 29 import java.io.IOException;
aoqi@0 30 import java.io.InputStream;
aoqi@0 31 import java.io.OutputStream;
aoqi@0 32
aoqi@0 33 import javax.activation.DataHandler;
aoqi@0 34 import javax.activation.DataSource;
aoqi@0 35 import javax.xml.stream.XMLStreamException;
aoqi@0 36
aoqi@0 37 import javax.xml.stream.XMLStreamWriter;
aoqi@0 38
aoqi@0 39 import com.sun.xml.internal.bind.DatatypeConverterImpl;
aoqi@0 40 import com.sun.xml.internal.bind.v2.runtime.XMLSerializer;
aoqi@0 41 import com.sun.xml.internal.bind.v2.runtime.output.Pcdata;
aoqi@0 42 import com.sun.xml.internal.bind.v2.runtime.output.UTF8XmlOutput;
aoqi@0 43 import com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx;
aoqi@0 44 import com.sun.istack.internal.Nullable;
aoqi@0 45
aoqi@0 46 /**
aoqi@0 47 * Fed to unmarshaller when the 'text' data is actually
aoqi@0 48 * a virtual image of base64 encoding of the binary data
aoqi@0 49 * transferred on the wire.
aoqi@0 50 *
aoqi@0 51 * Used for the MTOM support.
aoqi@0 52 *
aoqi@0 53 * This object is mutable and the owner of this object can
aoqi@0 54 * reuse it with new data.
aoqi@0 55 *
aoqi@0 56 * Also used by the marshaller to write out the binary data
aoqi@0 57 * that could be possibly attached.
aoqi@0 58 *
aoqi@0 59 * @see XmlVisitor#text(CharSequence)
aoqi@0 60 * @see XMLSerializer#text(Pcdata,String)
aoqi@0 61 *
aoqi@0 62 * @author Kohsuke Kawaguchi, Martin Grebac
aoqi@0 63 */
aoqi@0 64 public final class Base64Data extends Pcdata {
aoqi@0 65
aoqi@0 66 // either dataHandler or (data,dataLen,mimeType?) must be present
aoqi@0 67 private DataHandler dataHandler;
aoqi@0 68 private byte[] data;
aoqi@0 69 /**
aoqi@0 70 * Length of the valid data in {@link #data}.
aoqi@0 71 */
aoqi@0 72 private int dataLen;
aoqi@0 73 /**
aoqi@0 74 * Optional MIME type of {@link #data}.
aoqi@0 75 *
aoqi@0 76 * Unused when {@link #dataHandler} is set.
aoqi@0 77 * Use {@link DataHandler#getContentType()} in that case.
aoqi@0 78 */
aoqi@0 79 private @Nullable
aoqi@0 80 String mimeType;
aoqi@0 81
aoqi@0 82 /**
aoqi@0 83 * Fills in the data object by a portion of the byte[].
aoqi@0 84 *
aoqi@0 85 * @param len
aoqi@0 86 * data[0] to data[len-1] are treated as the data.
aoqi@0 87 */
aoqi@0 88 public void set(byte[] data, int len, @Nullable String mimeType) {
aoqi@0 89 this.data = data;
aoqi@0 90 this.dataLen = len;
aoqi@0 91 this.dataHandler = null;
aoqi@0 92 this.mimeType = mimeType;
aoqi@0 93 }
aoqi@0 94
aoqi@0 95 /**
aoqi@0 96 * Fills in the data object by the byte[] of the exact length.
aoqi@0 97 *
aoqi@0 98 * @param data
aoqi@0 99 * this buffer may be owned directly by the unmarshaleld JAXB object.
aoqi@0 100 */
aoqi@0 101 public void set(byte[] data, @Nullable String mimeType) {
aoqi@0 102 set(data, data.length, mimeType);
aoqi@0 103 }
aoqi@0 104
aoqi@0 105 /**
aoqi@0 106 * Fills in the data object by a {@link DataHandler}.
aoqi@0 107 */
aoqi@0 108 public void set(DataHandler data) {
aoqi@0 109 assert data != null;
aoqi@0 110 this.dataHandler = data;
aoqi@0 111 this.data = null;
aoqi@0 112 }
aoqi@0 113
aoqi@0 114 /**
aoqi@0 115 * Gets the raw data.
aoqi@0 116 */
aoqi@0 117 public DataHandler getDataHandler() {
aoqi@0 118 if (dataHandler == null) {
aoqi@0 119 dataHandler = new DataHandler(new DataSource() {
aoqi@0 120
aoqi@0 121 public String getContentType() {
aoqi@0 122 return getMimeType();
aoqi@0 123 }
aoqi@0 124
aoqi@0 125 public InputStream getInputStream() {
aoqi@0 126 return new ByteArrayInputStream(data, 0, dataLen);
aoqi@0 127 }
aoqi@0 128
aoqi@0 129 public String getName() {
aoqi@0 130 return null;
aoqi@0 131 }
aoqi@0 132
aoqi@0 133 public OutputStream getOutputStream() {
aoqi@0 134 throw new UnsupportedOperationException();
aoqi@0 135 }
aoqi@0 136 });
aoqi@0 137 }
aoqi@0 138
aoqi@0 139 return dataHandler;
aoqi@0 140 }
aoqi@0 141
aoqi@0 142 /**
aoqi@0 143 * Gets the byte[] of the exact length.
aoqi@0 144 */
aoqi@0 145 public byte[] getExact() {
aoqi@0 146 get();
aoqi@0 147 if (dataLen != data.length) {
aoqi@0 148 byte[] buf = new byte[dataLen];
aoqi@0 149 System.arraycopy(data, 0, buf, 0, dataLen);
aoqi@0 150 data = buf;
aoqi@0 151 }
aoqi@0 152 return data;
aoqi@0 153 }
aoqi@0 154
aoqi@0 155 /**
aoqi@0 156 * Gets the data as an {@link InputStream}.
aoqi@0 157 */
aoqi@0 158 public InputStream getInputStream() throws IOException {
aoqi@0 159 if (dataHandler != null) {
aoqi@0 160 return dataHandler.getInputStream();
aoqi@0 161 } else {
aoqi@0 162 return new ByteArrayInputStream(data, 0, dataLen);
aoqi@0 163 }
aoqi@0 164 }
aoqi@0 165
aoqi@0 166 /**
aoqi@0 167 * Returns false if this object only has {@link DataHandler} and therefore
aoqi@0 168 * {@link #get()} operation is likely going to be expensive.
aoqi@0 169 */
aoqi@0 170 public boolean hasData() {
aoqi@0 171 return data != null;
aoqi@0 172 }
aoqi@0 173
aoqi@0 174 /**
aoqi@0 175 * Gets the raw data. The size of the byte array maybe larger than the actual length.
aoqi@0 176 */
aoqi@0 177 public byte[] get() {
aoqi@0 178 if (data == null) {
aoqi@0 179 try {
aoqi@0 180 ByteArrayOutputStreamEx baos = new ByteArrayOutputStreamEx(1024);
aoqi@0 181 InputStream is = dataHandler.getDataSource().getInputStream();
aoqi@0 182 baos.readFrom(is);
aoqi@0 183 is.close();
aoqi@0 184 data = baos.getBuffer();
aoqi@0 185 dataLen = baos.size();
aoqi@0 186 } catch (IOException e) {
aoqi@0 187 // TODO: report the error to the unmarshaller
aoqi@0 188 dataLen = 0; // recover by assuming length-0 data
aoqi@0 189 }
aoqi@0 190 }
aoqi@0 191 return data;
aoqi@0 192 }
aoqi@0 193
aoqi@0 194 public int getDataLen() {
aoqi@0 195 return dataLen;
aoqi@0 196 }
aoqi@0 197
aoqi@0 198 public String getMimeType() {
aoqi@0 199 if (mimeType == null) {
aoqi@0 200 return "application/octet-stream";
aoqi@0 201 }
aoqi@0 202 return mimeType;
aoqi@0 203 }
aoqi@0 204
aoqi@0 205 /**
aoqi@0 206 * Gets the number of characters needed to represent
aoqi@0 207 * this binary data in the base64 encoding.
aoqi@0 208 */
aoqi@0 209 public int length() {
aoqi@0 210 // for each 3 bytes you use 4 chars
aoqi@0 211 // if the remainder is 1 or 2 there will be 4 more
aoqi@0 212 get(); // fill in the buffer if necessary
aoqi@0 213 return ((dataLen + 2) / 3) * 4;
aoqi@0 214 }
aoqi@0 215
aoqi@0 216 /**
aoqi@0 217 * Encode this binary data in the base64 encoding
aoqi@0 218 * and returns the character at the specified position.
aoqi@0 219 */
aoqi@0 220 public char charAt(int index) {
aoqi@0 221 // we assume that the length() method is called before this method
aoqi@0 222 // (otherwise how would the caller know that the index is valid?)
aoqi@0 223 // so we assume that the byte[] is already populated
aoqi@0 224
aoqi@0 225 int offset = index % 4;
aoqi@0 226 int base = (index / 4) * 3;
aoqi@0 227
aoqi@0 228 byte b1, b2;
aoqi@0 229
aoqi@0 230 switch (offset) {
aoqi@0 231 case 0:
aoqi@0 232 return DatatypeConverterImpl.encode(data[base] >> 2);
aoqi@0 233 case 1:
aoqi@0 234 if (base + 1 < dataLen) {
aoqi@0 235 b1 = data[base + 1];
aoqi@0 236 } else {
aoqi@0 237 b1 = 0;
aoqi@0 238 }
aoqi@0 239 return DatatypeConverterImpl.encode(
aoqi@0 240 ((data[base] & 0x3) << 4)
aoqi@0 241 | ((b1 >> 4) & 0xF));
aoqi@0 242 case 2:
aoqi@0 243 if (base + 1 < dataLen) {
aoqi@0 244 b1 = data[base + 1];
aoqi@0 245 if (base + 2 < dataLen) {
aoqi@0 246 b2 = data[base + 2];
aoqi@0 247 } else {
aoqi@0 248 b2 = 0;
aoqi@0 249 }
aoqi@0 250
aoqi@0 251 return DatatypeConverterImpl.encode(
aoqi@0 252 ((b1 & 0xF) << 2)
aoqi@0 253 | ((b2 >> 6) & 0x3));
aoqi@0 254 } else {
aoqi@0 255 return '=';
aoqi@0 256 }
aoqi@0 257 case 3:
aoqi@0 258 if (base + 2 < dataLen) {
aoqi@0 259 return DatatypeConverterImpl.encode(data[base + 2] & 0x3F);
aoqi@0 260 } else {
aoqi@0 261 return '=';
aoqi@0 262 }
aoqi@0 263 }
aoqi@0 264
aoqi@0 265 throw new IllegalStateException();
aoqi@0 266 }
aoqi@0 267
aoqi@0 268 /**
aoqi@0 269 * Internally this is only used to split a text to a list,
aoqi@0 270 * which doesn't happen that much for base64.
aoqi@0 271 * So this method should be smaller than faster.
aoqi@0 272 */
aoqi@0 273 public CharSequence subSequence(int start, int end) {
aoqi@0 274 StringBuilder buf = new StringBuilder();
aoqi@0 275 get(); // fill in the buffer if we haven't done so
aoqi@0 276 for (int i = start; i < end; i++) {
aoqi@0 277 buf.append(charAt(i));
aoqi@0 278 }
aoqi@0 279 return buf;
aoqi@0 280 }
aoqi@0 281
aoqi@0 282 /**
aoqi@0 283 * Returns the base64 encoded string of this data.
aoqi@0 284 */
aoqi@0 285 public String toString() {
aoqi@0 286 get(); // fill in the buffer
aoqi@0 287 return DatatypeConverterImpl._printBase64Binary(data, 0, dataLen);
aoqi@0 288 }
aoqi@0 289
aoqi@0 290 @Override
aoqi@0 291 public void writeTo(char[] buf, int start) {
aoqi@0 292 get();
aoqi@0 293 DatatypeConverterImpl._printBase64Binary(data, 0, dataLen, buf, start);
aoqi@0 294 }
aoqi@0 295
aoqi@0 296 public void writeTo(UTF8XmlOutput output) throws IOException {
aoqi@0 297 // TODO: this is inefficient if the data source is note byte[] but DataHandler
aoqi@0 298 get();
aoqi@0 299 output.text(data, dataLen);
aoqi@0 300 }
aoqi@0 301
aoqi@0 302 public void writeTo(XMLStreamWriter output) throws IOException, XMLStreamException {
aoqi@0 303 get();
aoqi@0 304 DatatypeConverterImpl._printBase64Binary(data, 0, dataLen, output);
aoqi@0 305 }
aoqi@0 306
aoqi@0 307 }

mercurial