12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604 |
- /*
- * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
- *
- * The Apache Software License, Version 1.1
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution, if
- * any, must include the following acknowlegement:
- * "This product includes software developed by the
- * Caucho Technology (http://www.caucho.com/)."
- * Alternately, this acknowlegement may appear in the software itself,
- * if and wherever such third-party acknowlegements normally appear.
- *
- * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
- * endorse or promote products derived from this software without prior
- * written permission. For written permission, please contact
- * info@caucho.com.
- *
- * 5. Products derived from this software may not be called "Resin"
- * nor may "Resin" appear in their names without prior written
- * permission of Caucho Technology.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @author Scott Ferguson
- */
- package com.hmsoft.remote.caucho.hessian.io;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.HashMap;
- import com.hmsoft.remote.caucho.hessian.util.IdentityIntMap;
- /**
- * Output stream for Hessian 2 requests.
- *
- * <p>Since HessianOutput does not depend on any classes other than
- * in the JDK, it can be extracted independently into a smaller package.
- *
- * <p>HessianOutput is unbuffered, so any client needs to provide
- * its own buffering.
- *
- * <pre>
- * OutputStream os = ...; // from http connection
- * Hessian2Output out = new Hessian2Output(os);
- * String value;
- *
- * out.startCall("hello", 1); // start hello call
- * out.writeString("arg1"); // write a string argument
- * out.completeCall(); // complete the call
- * </pre>
- */
- public class Hessian2Output
- extends AbstractHessianOutput
- implements Hessian2Constants
- {
- // the output stream/
- protected OutputStream _os;
-
- // map of references
- private IdentityIntMap _refs = new IdentityIntMap();
- private boolean _isCloseStreamOnClose;
-
- // map of classes
- private HashMap _classRefs;
-
- // map of types
- private HashMap _typeRefs;
- public final static int SIZE = 4096;
-
- private final byte []_buffer = new byte[SIZE];
- private int _offset;
- private boolean _isStreaming;
-
- /**
- * Creates a new Hessian output stream, initialized with an
- * underlying output stream.
- *
- * @param os the underlying output stream.
- */
- public Hessian2Output(OutputStream os)
- {
- _os = os;
- }
-
- public void setCloseStreamOnClose(boolean isClose)
- {
- _isCloseStreamOnClose = isClose;
- }
-
- public boolean isCloseStreamOnClose()
- {
- return _isCloseStreamOnClose;
- }
-
- /**
- * Writes a complete method call.
- */
- @Override
- public void call(String method, Object []args)
- throws IOException
- {
- int length = args != null ? args.length : 0;
-
- startCall(method, length);
-
- for (int i = 0; i < args.length; i++)
- writeObject(args[i]);
-
- completeCall();
- }
-
- /**
- * Starts the method call. Clients would use <code>startCall</code>
- * instead of <code>call</code> if they wanted finer control over
- * writing the arguments, or needed to write headers.
- *
- * <code><pre>
- * C
- * string # method name
- * int # arg count
- * </pre></code>
- *
- * @param method the method name to call.
- */
- public void startCall(String method, int length)
- throws IOException
- {
- int offset = _offset;
- if (SIZE < offset + 32) {
- flush();
- offset = _offset;
- }
- byte []buffer = _buffer;
-
- buffer[_offset++] = (byte) 'C';
- writeString(method);
- writeInt(length);
- }
- /**
- * Writes the call tag. This would be followed by the
- * method and the arguments
- *
- * <code><pre>
- * C
- * </pre></code>
- *
- * @param method the method name to call.
- */
- public void startCall()
- throws IOException
- {
- flushIfFull();
-
- _buffer[_offset++] = (byte) 'C';
- }
-
- /**
- * Starts an envelope.
- *
- * <code><pre>
- * E major minor
- * m b16 b8 method-name
- * </pre></code>
- *
- * @param method the method name to call.
- */
- public void startEnvelope(String method)
- throws IOException
- {
- int offset = _offset;
- if (SIZE < offset + 32) {
- flush();
- offset = _offset;
- }
- _buffer[_offset++] = (byte) 'E';
- writeString(method);
- }
- /**
- * Completes an envelope.
- *
- * <p>A successful completion will have a single value:
- *
- * <pre>
- * Z
- * </pre>
- */
- public void completeEnvelope()
- throws IOException
- {
- flushIfFull();
-
- _buffer[_offset++] = (byte) 'Z';
- }
- /**
- * Writes the method tag.
- *
- * <code><pre>
- * string
- * </pre></code>
- *
- * @param method the method name to call.
- */
- public void writeMethod(String method)
- throws IOException
- {
- writeString(method);
- }
- /**
- * Completes.
- *
- * <code><pre>
- * z
- * </pre></code>
- */
- public void completeCall()
- throws IOException
- {
- /*
- flushIfFull();
-
- _buffer[_offset++] = (byte) 'Z';
- */
- }
- /**
- * Starts the reply
- *
- * <p>A successful completion will have a single value:
- *
- * <pre>
- * R
- * </pre>
- */
- public void startReply()
- throws IOException
- {
- writeVersion();
-
- flushIfFull();
- _buffer[_offset++] = (byte) 'R';
- }
-
- public void writeVersion()
- throws IOException
- {
- flushIfFull();
- _buffer[_offset++] = (byte) 'H';
- _buffer[_offset++] = (byte) 2;
- _buffer[_offset++] = (byte) 0;
- }
- /**
- * Completes reading the reply
- *
- * <p>A successful completion will have a single value:
- *
- * <pre>
- * z
- * </pre>
- */
- public void completeReply()
- throws IOException
- {
- }
- /**
- * Starts a packet
- *
- * <p>A message contains several objects encapsulated by a length</p>
- *
- * <pre>
- * p x02 x00
- * </pre>
- */
- public void startMessage()
- throws IOException
- {
- flushIfFull();
-
- _buffer[_offset++] = (byte) 'p';
- _buffer[_offset++] = (byte) 2;
- _buffer[_offset++] = (byte) 0;
- }
- /**
- * Completes reading the message
- *
- * <p>A successful completion will have a single value:
- *
- * <pre>
- * z
- * </pre>
- */
- public void completeMessage()
- throws IOException
- {
- flushIfFull();
-
- _buffer[_offset++] = (byte) 'z';
- }
- /**
- * Writes a fault. The fault will be written
- * as a descriptive string followed by an object:
- *
- * <code><pre>
- * F map
- * </pre></code>
- *
- * <code><pre>
- * F H
- * \x04code
- * \x10the fault code
- *
- * \x07message
- * \x11the fault message
- *
- * \x06detail
- * M\xnnjavax.ejb.FinderException
- * ...
- * Z
- * Z
- * </pre></code>
- *
- * @param code the fault code, a three digit
- */
- public void writeFault(String code, String message, Object detail)
- throws IOException
- {
- flushIfFull();
- writeVersion();
-
- _buffer[_offset++] = (byte) 'F';
- _buffer[_offset++] = (byte) 'H';
- _refs.put(new HashMap(), _refs.size());
- writeString("code");
- writeString(code);
- writeString("message");
- writeString(message);
- if (detail != null) {
- writeString("detail");
- writeObject(detail);
- }
- flushIfFull();
- _buffer[_offset++] = (byte) 'Z';
- }
- /**
- * Writes any object to the output stream.
- */
- public void writeObject(Object object)
- throws IOException
- {
- if (object == null) {
- writeNull();
- return;
- }
- Serializer serializer;
- serializer = findSerializerFactory().getSerializer(object.getClass());
- serializer.writeObject(object, this);
- }
- /**
- * Writes the list header to the stream. List writers will call
- * <code>writeListBegin</code> followed by the list contents and then
- * call <code>writeListEnd</code>.
- *
- * <code><pre>
- * list ::= V type value* Z
- * ::= v type int value*
- * </pre></code>
- *
- * @return true for variable lists, false for fixed lists
- */
- public boolean writeListBegin(int length, String type)
- throws IOException
- {
- flushIfFull();
- if (length < 0) {
- if (type != null) {
- _buffer[_offset++] = (byte) BC_LIST_VARIABLE;
- writeType(type);
- }
- else
- _buffer[_offset++] = (byte) BC_LIST_VARIABLE_UNTYPED;
- return true;
- }
- else if (length <= LIST_DIRECT_MAX) {
- if (type != null) {
- _buffer[_offset++] = (byte) (BC_LIST_DIRECT + length);
- writeType(type);
- }
- else {
- _buffer[_offset++] = (byte) (BC_LIST_DIRECT_UNTYPED + length);
- }
- return false;
- }
- else {
- if (type != null) {
- _buffer[_offset++] = (byte) BC_LIST_FIXED;
- writeType(type);
- }
- else {
- _buffer[_offset++] = (byte) BC_LIST_FIXED_UNTYPED;
- }
-
- writeInt(length);
- return false;
- }
- }
- /**
- * Writes the tail of the list to the stream for a variable-length list.
- */
- public void writeListEnd()
- throws IOException
- {
- flushIfFull();
-
- _buffer[_offset++] = (byte) BC_END;
- }
- /**
- * Writes the map header to the stream. Map writers will call
- * <code>writeMapBegin</code> followed by the map contents and then
- * call <code>writeMapEnd</code>.
- *
- * <code><pre>
- * map ::= M type (<value> <value>)* Z
- * ::= H (<value> <value>)* Z
- * </pre></code>
- */
- public void writeMapBegin(String type)
- throws IOException
- {
- if (SIZE < _offset + 32)
- flush();
- if (type != null) {
- _buffer[_offset++] = BC_MAP;
- writeType(type);
- }
- else
- _buffer[_offset++] = BC_MAP_UNTYPED;
- }
- /**
- * Writes the tail of the map to the stream.
- */
- public void writeMapEnd()
- throws IOException
- {
- if (SIZE < _offset + 32)
- flush();
-
- _buffer[_offset++] = (byte) BC_END;
- }
- /**
- * Writes the object definition
- *
- * <code><pre>
- * C <string> <int> <string>*
- * </pre></code>
- */
- public int writeObjectBegin(String type)
- throws IOException
- {
- if (_classRefs == null)
- _classRefs = new HashMap();
- Integer refV = (Integer) _classRefs.get(type);
- if (refV != null) {
- int ref = refV.intValue();
-
- if (SIZE < _offset + 32)
- flush();
- if (ref <= OBJECT_DIRECT_MAX) {
- _buffer[_offset++] = (byte) (BC_OBJECT_DIRECT + ref);
- }
- else {
- _buffer[_offset++] = (byte) 'O';
- writeInt(ref);
- }
- return ref;
- }
- else {
- int ref = _classRefs.size();
-
- _classRefs.put(type, Integer.valueOf(ref));
-
- if (SIZE < _offset + 32)
- flush();
- _buffer[_offset++] = (byte) 'C';
- writeString(type);
- return -1;
- }
- }
- /**
- * Writes the tail of the class definition to the stream.
- */
- public void writeClassFieldLength(int len)
- throws IOException
- {
- writeInt(len);
- }
- /**
- * Writes the tail of the object definition to the stream.
- */
- public void writeObjectEnd()
- throws IOException
- {
- }
- /**
- * <code><pre>
- * type ::= string
- * ::= int
- * </code></pre>
- */
- private void writeType(String type)
- throws IOException
- {
- flushIfFull();
-
- int len = type.length();
- if (len == 0) {
- throw new IllegalArgumentException("empty type is not allowed");
- }
- if (_typeRefs == null)
- _typeRefs = new HashMap();
- Integer typeRefV = (Integer) _typeRefs.get(type);
-
- if (typeRefV != null) {
- int typeRef = typeRefV.intValue();
-
- writeInt(typeRef);
- }
- else {
- _typeRefs.put(type, Integer.valueOf(_typeRefs.size()));
- writeString(type);
- }
- }
- /**
- * Writes a boolean value to the stream. The boolean will be written
- * with the following syntax:
- *
- * <code><pre>
- * T
- * F
- * </pre></code>
- *
- * @param value the boolean value to write.
- */
- public void writeBoolean(boolean value)
- throws IOException
- {
- if (SIZE < _offset + 16)
- flush();
- if (value)
- _buffer[_offset++] = (byte) 'T';
- else
- _buffer[_offset++] = (byte) 'F';
- }
- /**
- * Writes an integer value to the stream. The integer will be written
- * with the following syntax:
- *
- * <code><pre>
- * I b32 b24 b16 b8
- * </pre></code>
- *
- * @param value the integer value to write.
- */
- public void writeInt(int value)
- throws IOException
- {
- int offset = _offset;
- byte []buffer = _buffer;
- if (SIZE <= offset + 16) {
- flush();
- offset = _offset;
- }
-
- if (INT_DIRECT_MIN <= value && value <= INT_DIRECT_MAX)
- buffer[offset++] = (byte) (value + BC_INT_ZERO);
- else if (INT_BYTE_MIN <= value && value <= INT_BYTE_MAX) {
- buffer[offset++] = (byte) (BC_INT_BYTE_ZERO + (value >> 8));
- buffer[offset++] = (byte) (value);
- }
- else if (INT_SHORT_MIN <= value && value <= INT_SHORT_MAX) {
- buffer[offset++] = (byte) (BC_INT_SHORT_ZERO + (value >> 16));
- buffer[offset++] = (byte) (value >> 8);
- buffer[offset++] = (byte) (value);
- }
- else {
- buffer[offset++] = (byte) ('I');
- buffer[offset++] = (byte) (value >> 24);
- buffer[offset++] = (byte) (value >> 16);
- buffer[offset++] = (byte) (value >> 8);
- buffer[offset++] = (byte) (value);
- }
- _offset = offset;
- }
- /**
- * Writes a long value to the stream. The long will be written
- * with the following syntax:
- *
- * <code><pre>
- * L b64 b56 b48 b40 b32 b24 b16 b8
- * </pre></code>
- *
- * @param value the long value to write.
- */
- public void writeLong(long value)
- throws IOException
- {
- int offset = _offset;
- byte []buffer = _buffer;
- if (SIZE <= offset + 16) {
- flush();
- offset = _offset;
- }
- if (LONG_DIRECT_MIN <= value && value <= LONG_DIRECT_MAX) {
- buffer[offset++] = (byte) (value + BC_LONG_ZERO);
- }
- else if (LONG_BYTE_MIN <= value && value <= LONG_BYTE_MAX) {
- buffer[offset++] = (byte) (BC_LONG_BYTE_ZERO + (value >> 8));
- buffer[offset++] = (byte) (value);
- }
- else if (LONG_SHORT_MIN <= value && value <= LONG_SHORT_MAX) {
- buffer[offset++] = (byte) (BC_LONG_SHORT_ZERO + (value >> 16));
- buffer[offset++] = (byte) (value >> 8);
- buffer[offset++] = (byte) (value);
- }
- else if (-0x80000000L <= value && value <= 0x7fffffffL) {
- buffer[offset + 0] = (byte) BC_LONG_INT;
- buffer[offset + 1] = (byte) (value >> 24);
- buffer[offset + 2] = (byte) (value >> 16);
- buffer[offset + 3] = (byte) (value >> 8);
- buffer[offset + 4] = (byte) (value);
- offset += 5;
- }
- else {
- buffer[offset + 0] = (byte) 'L';
- buffer[offset + 1] = (byte) (value >> 56);
- buffer[offset + 2] = (byte) (value >> 48);
- buffer[offset + 3] = (byte) (value >> 40);
- buffer[offset + 4] = (byte) (value >> 32);
- buffer[offset + 5] = (byte) (value >> 24);
- buffer[offset + 6] = (byte) (value >> 16);
- buffer[offset + 7] = (byte) (value >> 8);
- buffer[offset + 8] = (byte) (value);
- offset += 9;
- }
- _offset = offset;
- }
- /**
- * Writes a double value to the stream. The double will be written
- * with the following syntax:
- *
- * <code><pre>
- * D b64 b56 b48 b40 b32 b24 b16 b8
- * </pre></code>
- *
- * @param value the double value to write.
- */
- public void writeDouble(double value)
- throws IOException
- {
- int offset = _offset;
- byte []buffer = _buffer;
- if (SIZE <= offset + 16) {
- flush();
- offset = _offset;
- }
-
- int intValue = (int) value;
-
- if (intValue == value) {
- if (intValue == 0) {
- buffer[offset++] = (byte) BC_DOUBLE_ZERO;
- _offset = offset;
- return;
- }
- else if (intValue == 1) {
- buffer[offset++] = (byte) BC_DOUBLE_ONE;
- _offset = offset;
- return;
- }
- else if (-0x80 <= intValue && intValue < 0x80) {
- buffer[offset++] = (byte) BC_DOUBLE_BYTE;
- buffer[offset++] = (byte) intValue;
- _offset = offset;
- return;
- }
- else if (-0x8000 <= intValue && intValue < 0x8000) {
- buffer[offset + 0] = (byte) BC_DOUBLE_SHORT;
- buffer[offset + 1] = (byte) (intValue >> 8);
- buffer[offset + 2] = (byte) intValue;
- _offset = offset + 3;
-
- return;
- }
- }
- int mills = (int) (value * 1000);
- if (0.001 * mills == value) {
- buffer[offset + 0] = (byte) (BC_DOUBLE_MILL);
- buffer[offset + 1] = (byte) (mills >> 24);
- buffer[offset + 2] = (byte) (mills >> 16);
- buffer[offset + 3] = (byte) (mills >> 8);
- buffer[offset + 4] = (byte) (mills);
- _offset = offset + 5;
- return;
- }
-
- long bits = Double.doubleToLongBits(value);
-
- buffer[offset + 0] = (byte) 'D';
- buffer[offset + 1] = (byte) (bits >> 56);
- buffer[offset + 2] = (byte) (bits >> 48);
- buffer[offset + 3] = (byte) (bits >> 40);
- buffer[offset + 4] = (byte) (bits >> 32);
- buffer[offset + 5] = (byte) (bits >> 24);
- buffer[offset + 6] = (byte) (bits >> 16);
- buffer[offset + 7] = (byte) (bits >> 8);
- buffer[offset + 8] = (byte) (bits);
- _offset = offset + 9;
- }
- /**
- * Writes a date to the stream.
- *
- * <code><pre>
- * date ::= d b7 b6 b5 b4 b3 b2 b1 b0
- * ::= x65 b3 b2 b1 b0
- * </pre></code>
- *
- * @param time the date in milliseconds from the epoch in UTC
- */
- public void writeUTCDate(long time)
- throws IOException
- {
- if (SIZE < _offset + 32)
- flush();
- int offset = _offset;
- byte []buffer = _buffer;
- if (time % 60000L == 0) {
- // compact date ::= x65 b3 b2 b1 b0
-
- long minutes = time / 60000L;
- if ((minutes >> 31) == 0 || (minutes >> 31) == -1) {
- buffer[offset++] = (byte) BC_DATE_MINUTE;
- buffer[offset++] = ((byte) (minutes >> 24));
- buffer[offset++] = ((byte) (minutes >> 16));
- buffer[offset++] = ((byte) (minutes >> 8));
- buffer[offset++] = ((byte) (minutes >> 0));
- _offset = offset;
- return;
- }
- }
- buffer[offset++] = (byte) BC_DATE;
- buffer[offset++] = ((byte) (time >> 56));
- buffer[offset++] = ((byte) (time >> 48));
- buffer[offset++] = ((byte) (time >> 40));
- buffer[offset++] = ((byte) (time >> 32));
- buffer[offset++] = ((byte) (time >> 24));
- buffer[offset++] = ((byte) (time >> 16));
- buffer[offset++] = ((byte) (time >> 8));
- buffer[offset++] = ((byte) (time));
- _offset = offset;
- }
- /**
- * Writes a null value to the stream.
- * The null will be written with the following syntax
- *
- * <code><pre>
- * N
- * </pre></code>
- *
- * @param value the string value to write.
- */
- public void writeNull()
- throws IOException
- {
- int offset = _offset;
- byte []buffer = _buffer;
- if (SIZE <= offset + 16) {
- flush();
- offset = _offset;
- }
- buffer[offset++] = 'N';
- _offset = offset;
- }
- /**
- * Writes a string value to the stream using UTF-8 encoding.
- * The string will be written with the following syntax:
- *
- * <code><pre>
- * S b16 b8 string-value
- * </pre></code>
- *
- * If the value is null, it will be written as
- *
- * <code><pre>
- * N
- * </pre></code>
- *
- * @param value the string value to write.
- */
- public void writeString(String value)
- throws IOException
- {
- int offset = _offset;
- byte []buffer = _buffer;
- if (SIZE <= offset + 16) {
- flush();
- offset = _offset;
- }
-
- if (value == null) {
- buffer[offset++] = (byte) 'N';
- _offset = offset;
- }
- else {
- int length = value.length();
- int strOffset = 0;
-
- while (length > 0x8000) {
- int sublen = 0x8000;
- offset = _offset;
- if (SIZE <= offset + 16) {
- flush();
- offset = _offset;
- }
- // chunk can't end in high surrogate
- char tail = value.charAt(strOffset + sublen - 1);
- if (0xd800 <= tail && tail <= 0xdbff)
- sublen--;
- buffer[offset + 0] = (byte) BC_STRING_CHUNK;
- buffer[offset + 1] = (byte) (sublen >> 8);
- buffer[offset + 2] = (byte) (sublen);
- _offset = offset + 3;
- printString(value, strOffset, sublen);
- length -= sublen;
- strOffset += sublen;
- }
- offset = _offset;
- if (SIZE <= offset + 16) {
- flush();
- offset = _offset;
- }
- if (length <= STRING_DIRECT_MAX) {
- buffer[offset++] = (byte) (BC_STRING_DIRECT + length);
- }
- else if (length <= STRING_SHORT_MAX) {
- buffer[offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
- buffer[offset++] = (byte) (length);
- }
- else {
- buffer[offset++] = (byte) ('S');
- buffer[offset++] = (byte) (length >> 8);
- buffer[offset++] = (byte) (length);
- }
- _offset = offset;
- printString(value, strOffset, length);
- }
- }
- /**
- * Writes a string value to the stream using UTF-8 encoding.
- * The string will be written with the following syntax:
- *
- * <code><pre>
- * S b16 b8 string-value
- * </pre></code>
- *
- * If the value is null, it will be written as
- *
- * <code><pre>
- * N
- * </pre></code>
- *
- * @param value the string value to write.
- */
- public void writeString(char []buffer, int offset, int length)
- throws IOException
- {
- if (buffer == null) {
- if (SIZE < _offset + 16)
- flush();
-
- _buffer[_offset++] = (byte) ('N');
- }
- else {
- while (length > 0x8000) {
- int sublen = 0x8000;
- if (SIZE < _offset + 16)
- flush();
- // chunk can't end in high surrogate
- char tail = buffer[offset + sublen - 1];
- if (0xd800 <= tail && tail <= 0xdbff)
- sublen--;
-
- _buffer[_offset++] = (byte) BC_STRING_CHUNK;
- _buffer[_offset++] = (byte) (sublen >> 8);
- _buffer[_offset++] = (byte) (sublen);
- printString(buffer, offset, sublen);
- length -= sublen;
- offset += sublen;
- }
- if (SIZE < _offset + 16)
- flush();
-
- if (length <= STRING_DIRECT_MAX) {
- _buffer[_offset++] = (byte) (BC_STRING_DIRECT + length);
- }
- else if (length <= STRING_SHORT_MAX) {
- _buffer[_offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
- _buffer[_offset++] = (byte) length;
- }
- else {
- _buffer[_offset++] = (byte) ('S');
- _buffer[_offset++] = (byte) (length >> 8);
- _buffer[_offset++] = (byte) (length);
- }
- printString(buffer, offset, length);
- }
- }
- /**
- * Writes a byte array to the stream.
- * The array will be written with the following syntax:
- *
- * <code><pre>
- * B b16 b18 bytes
- * </pre></code>
- *
- * If the value is null, it will be written as
- *
- * <code><pre>
- * N
- * </pre></code>
- *
- * @param value the string value to write.
- */
- public void writeBytes(byte []buffer)
- throws IOException
- {
- if (buffer == null) {
- if (SIZE < _offset + 16)
- flush();
- _buffer[_offset++] = 'N';
- }
- else
- writeBytes(buffer, 0, buffer.length);
- }
-
- /**
- * Writes a byte array to the stream.
- * The array will be written with the following syntax:
- *
- * <code><pre>
- * B b16 b18 bytes
- * </pre></code>
- *
- * If the value is null, it will be written as
- *
- * <code><pre>
- * N
- * </pre></code>
- *
- * @param value the string value to write.
- */
- public void writeBytes(byte []buffer, int offset, int length)
- throws IOException
- {
- if (buffer == null) {
- if (SIZE < _offset + 16)
- flushBuffer();
-
- _buffer[_offset++] = (byte) 'N';
- }
- else {
- flush();
- while (SIZE - _offset - 3 < length) {
- int sublen = SIZE - _offset - 3;
- if (sublen < 16) {
- flushBuffer();
- sublen = SIZE - _offset - 3;
- if (length < sublen)
- sublen = length;
- }
- _buffer[_offset++] = (byte) BC_BINARY_CHUNK;
- _buffer[_offset++] = (byte) (sublen >> 8);
- _buffer[_offset++] = (byte) sublen;
- System.arraycopy(buffer, offset, _buffer, _offset, sublen);
- _offset += sublen;
- length -= sublen;
- offset += sublen;
-
- flushBuffer();
- }
- if (SIZE < _offset + 16)
- flushBuffer();
- if (length <= BINARY_DIRECT_MAX) {
- _buffer[_offset++] = (byte) (BC_BINARY_DIRECT + length);
- }
- else if (length <= BINARY_SHORT_MAX) {
- _buffer[_offset++] = (byte) (BC_BINARY_SHORT + (length >> 8));
- _buffer[_offset++] = (byte) (length);
- }
- else {
- _buffer[_offset++] = (byte) 'B';
- _buffer[_offset++] = (byte) (length >> 8);
- _buffer[_offset++] = (byte) (length);
- }
- System.arraycopy(buffer, offset, _buffer, _offset, length);
- _offset += length;
- }
- }
-
- /**
- * Writes a byte buffer to the stream.
- *
- * <code><pre>
- * </pre></code>
- */
- public void writeByteBufferStart()
- throws IOException
- {
- }
-
- /**
- * Writes a byte buffer to the stream.
- *
- * <code><pre>
- * b b16 b18 bytes
- * </pre></code>
- */
- public void writeByteBufferPart(byte []buffer, int offset, int length)
- throws IOException
- {
- while (length > 0) {
- int sublen = length;
- if (0x8000 < sublen)
- sublen = 0x8000;
- flush(); // bypass buffer
-
- _os.write(BC_BINARY_CHUNK);
- _os.write(sublen >> 8);
- _os.write(sublen);
- _os.write(buffer, offset, sublen);
- length -= sublen;
- offset += sublen;
- }
- }
-
- /**
- * Writes a byte buffer to the stream.
- *
- * <code><pre>
- * b b16 b18 bytes
- * </pre></code>
- */
- public void writeByteBufferEnd(byte []buffer, int offset, int length)
- throws IOException
- {
- writeBytes(buffer, offset, length);
- }
- /**
- * Returns an output stream to write binary data.
- */
- public OutputStream getBytesOutputStream()
- throws IOException
- {
- return new BytesOutputStream();
- }
- /**
- * Writes a reference.
- *
- * <code><pre>
- * x51 <int>
- * </pre></code>
- *
- * @param value the integer value to write.
- */
- @Override
- protected void writeRef(int value)
- throws IOException
- {
- if (SIZE < _offset + 16)
- flush();
-
- _buffer[_offset++] = (byte) BC_REF;
-
- writeInt(value);
- }
- /**
- * If the object has already been written, just write its ref.
- *
- * @return true if we're writing a ref.
- */
- public boolean addRef(Object object)
- throws IOException
- {
- int ref = _refs.get(object);
- if (ref >= 0) {
- writeRef(ref);
-
- return true;
- }
- else {
- _refs.put(object, _refs.size());
-
- return false;
- }
- }
- /**
- * Removes a reference.
- */
- public boolean removeRef(Object obj)
- throws IOException
- {
- if (_refs != null) {
- _refs.remove(obj);
- return true;
- }
- else
- return false;
- }
- /**
- * Replaces a reference from one object to another.
- */
- public boolean replaceRef(Object oldRef, Object newRef)
- throws IOException
- {
- Integer value = (Integer) _refs.remove(oldRef);
- if (value != null) {
- _refs.put(newRef, value);
- return true;
- }
- else
- return false;
- }
- /**
- * Resets the references for streaming.
- */
- public void resetReferences()
- {
- if (_refs != null)
- _refs.clear();
- }
- /**
- * Starts the streaming message
- *
- * <p>A streaming message starts with 'P'</p>
- *
- * <pre>
- * P x02 x00
- * </pre>
- */
- public void writeStreamingObject(Object obj)
- throws IOException
- {
- startStreamingPacket();
- writeObject(obj);
- endStreamingPacket();
- }
- /**
- * Starts a streaming packet
- *
- * <p>A streaming message starts with 'P'</p>
- *
- * <pre>
- * P x02 x00
- * </pre>
- */
- public void startStreamingPacket()
- throws IOException
- {
- if (_refs != null)
- _refs.clear();
-
- flush();
- _isStreaming = true;
- _offset = 3;
- }
- public void endStreamingPacket()
- throws IOException
- {
- int len = _offset - 3;
-
- _buffer[0] = (byte) 'P';
- _buffer[1] = (byte) (len >> 8);
- _buffer[2] = (byte) len;
- _isStreaming = false;
- flush();
- }
- /**
- * Prints a string to the stream, encoded as UTF-8 with preceeding length
- *
- * @param v the string to print.
- */
- public void printLenString(String v)
- throws IOException
- {
- if (SIZE < _offset + 16)
- flush();
-
- if (v == null) {
- _buffer[_offset++] = (byte) (0);
- _buffer[_offset++] = (byte) (0);
- }
- else {
- int len = v.length();
- _buffer[_offset++] = (byte) (len >> 8);
- _buffer[_offset++] = (byte) (len);
- printString(v, 0, len);
- }
- }
- /**
- * Prints a string to the stream, encoded as UTF-8
- *
- * @param v the string to print.
- */
- public void printString(String v)
- throws IOException
- {
- printString(v, 0, v.length());
- }
-
- /**
- * Prints a string to the stream, encoded as UTF-8
- *
- * @param v the string to print.
- */
- public void printString(String v, int strOffset, int length)
- throws IOException
- {
- int offset = _offset;
- byte []buffer = _buffer;
-
- for (int i = 0; i < length; i++) {
- if (SIZE <= offset + 16) {
- _offset = offset;
- flush();
- offset = _offset;
- }
-
- char ch = v.charAt(i + strOffset);
- if (ch < 0x80)
- buffer[offset++] = (byte) (ch);
- else if (ch < 0x800) {
- buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
- buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
- }
- else {
- buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
- buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
- buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
- }
- }
- _offset = offset;
- }
-
- /**
- * Prints a string to the stream, encoded as UTF-8
- *
- * @param v the string to print.
- */
- public void printString(char []v, int strOffset, int length)
- throws IOException
- {
- int offset = _offset;
- byte []buffer = _buffer;
-
- for (int i = 0; i < length; i++) {
- if (SIZE <= offset + 16) {
- _offset = offset;
- flush();
- offset = _offset;
- }
-
- char ch = v[i + strOffset];
- if (ch < 0x80)
- buffer[offset++] = (byte) (ch);
- else if (ch < 0x800) {
- buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
- buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
- }
- else {
- buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
- buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
- buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
- }
- }
- _offset = offset;
- }
-
- private final void flushIfFull()
- throws IOException
- {
- int offset = _offset;
-
- if (SIZE < offset + 32) {
- _offset = 0;
- _os.write(_buffer, 0, offset);
- }
- }
- public final void flush()
- throws IOException
- {
- flushBuffer();
- if (_os != null)
- _os.flush();
- }
- public final void flushBuffer()
- throws IOException
- {
- int offset = _offset;
- if (! _isStreaming && offset > 0) {
- _offset = 0;
-
- _os.write(_buffer, 0, offset);
- }
- else if (_isStreaming && offset > 3) {
- int len = offset - 3;
- _buffer[0] = 'p';
- _buffer[1] = (byte) (len >> 8);
- _buffer[2] = (byte) len;
- _offset = 3;
- _os.write(_buffer, 0, offset);
- }
- }
- public final void close()
- throws IOException
- {
- // hessian/3a8c
- flush();
-
- OutputStream os = _os;
- _os = null;
- if (os != null) {
- if (_isCloseStreamOnClose)
- os.close();
- }
- }
- class BytesOutputStream extends OutputStream {
- private int _startOffset;
-
- BytesOutputStream()
- throws IOException
- {
- if (SIZE < _offset + 16) {
- Hessian2Output.this.flush();
- }
- _startOffset = _offset;
- _offset += 3; // skip 'b' xNN xNN
- }
- @Override
- public void write(int ch)
- throws IOException
- {
- if (SIZE <= _offset) {
- int length = (_offset - _startOffset) - 3;
- _buffer[_startOffset] = (byte) BC_BINARY_CHUNK;
- _buffer[_startOffset + 1] = (byte) (length >> 8);
- _buffer[_startOffset + 2] = (byte) (length);
- Hessian2Output.this.flush();
- _startOffset = _offset;
- _offset += 3;
- }
- _buffer[_offset++] = (byte) ch;
- }
- @Override
- public void write(byte []buffer, int offset, int length)
- throws IOException
- {
- while (length > 0) {
- int sublen = SIZE - _offset;
- if (length < sublen)
- sublen = length;
- if (sublen > 0) {
- System.arraycopy(buffer, offset, _buffer, _offset, sublen);
- _offset += sublen;
- }
- length -= sublen;
- offset += sublen;
- if (SIZE <= _offset) {
- int chunkLength = (_offset - _startOffset) - 3;
- _buffer[_startOffset] = (byte) BC_BINARY_CHUNK;
- _buffer[_startOffset + 1] = (byte) (chunkLength >> 8);
- _buffer[_startOffset + 2] = (byte) (chunkLength);
- Hessian2Output.this.flush();
- _startOffset = _offset;
- _offset += 3;
- }
- }
- }
- @Override
- public void close()
- throws IOException
- {
- int startOffset = _startOffset;
- _startOffset = -1;
- if (startOffset < 0)
- return;
- int length = (_offset - startOffset) - 3;
- _buffer[startOffset] = (byte) 'B';
- _buffer[startOffset + 1] = (byte) (length >> 8);
- _buffer[startOffset + 2] = (byte) (length);
- Hessian2Output.this.flush();
- }
- }
- }
|