001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2013 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020
021 package org.granite.messaging.jmf.codec.std.impl;
022
023 import java.io.IOException;
024 import java.io.OutputStream;
025
026 import org.granite.messaging.jmf.DumpContext;
027 import org.granite.messaging.jmf.InputContext;
028 import org.granite.messaging.jmf.OutputContext;
029 import org.granite.messaging.jmf.codec.std.DoubleCodec;
030 import org.granite.messaging.jmf.codec.std.LongCodec;
031
032 /**
033 * @author Franck WOLFF
034 */
035 public class DoubleCodecImpl extends AbstractStandardCodec<Double> implements DoubleCodec {
036
037 public int getObjectType() {
038 return JMF_DOUBLE_OBJECT;
039 }
040
041 public Class<?> getObjectClass() {
042 return Double.class;
043 }
044
045 public int getPrimitiveType() {
046 return JMF_DOUBLE;
047 }
048
049 public Class<?> getPrimitiveClass() {
050 return Double.TYPE;
051 }
052
053 public void encode(OutputContext ctx, Double v) throws IOException {
054 writeDoubleData(ctx, JMF_DOUBLE_OBJECT, v.doubleValue());
055 }
056
057 public Double decode(InputContext ctx, int parameterizedJmfType) throws IOException {
058 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
059
060 if (jmfType != JMF_DOUBLE_OBJECT)
061 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
062
063 return Double.valueOf(readDoubleData(ctx, parameterizedJmfType));
064 }
065
066 public void encodePrimitive(OutputContext ctx, double v) throws IOException {
067 writeDoubleData(ctx, JMF_DOUBLE, v);
068 }
069
070 public double decodePrimitive(InputContext ctx) throws IOException {
071 int parameterizedJmfType = ctx.safeRead();
072 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
073
074 if (jmfType != JMF_DOUBLE)
075 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
076
077 return readDoubleData(ctx, parameterizedJmfType);
078 }
079
080 public void dump(DumpContext ctx, int parameterizedJmfType) throws IOException {
081 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType);
082
083 switch (jmfType) {
084 case JMF_DOUBLE:
085 ctx.indentPrintLn("double: " + readDoubleData(ctx, parameterizedJmfType));
086 break;
087 case JMF_DOUBLE_OBJECT:
088 ctx.indentPrintLn(Double.class.getName() + ": " + Double.valueOf(readDoubleData(ctx, parameterizedJmfType)));
089 break;
090 default:
091 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType);
092 }
093 }
094
095 public static void writeDoubleData(OutputContext ctx, int jmfType, double v) throws IOException {
096 final OutputStream os = ctx.getOutputStream();
097
098 if (Double.isNaN(v))
099 os.write(0xC0 | jmfType);
100 else {
101 long asLong = (long)v;
102 LongCodec longCodec = ctx.getSharedContext().getCodecRegistry().getLongCodec();
103
104 int lengthAsLong = Integer.MAX_VALUE;
105 if (v == asLong) {
106 if (v == Long.MIN_VALUE)
107 lengthAsLong = 1;
108 else if (Double.doubleToRawLongBits(v) != Long.MIN_VALUE)
109 lengthAsLong = longCodec.lengthOfVariableAbsoluteLong(Math.abs(asLong)) + 1;
110 }
111
112 if (lengthAsLong < 4) {
113 os.write(0x80 | jmfType);
114 longCodec.writeVariableLong(ctx, asLong);
115 }
116 else if (v == (float)v) {
117 os.write(0x40 | jmfType);
118
119 int bits = Float.floatToIntBits((float)v);
120 os.write(bits);
121 os.write(bits >> 8);
122 os.write(bits >> 16);
123 os.write(bits >> 24);
124 }
125 else if (lengthAsLong < 8) {
126 os.write(0x80 | jmfType);
127 longCodec.writeVariableLong(ctx, asLong);
128 }
129 else {
130 os.write(jmfType);
131
132 long bits = Double.doubleToLongBits(v);
133 os.write((int)bits);
134 os.write((int)(bits >> 8));
135 os.write((int)(bits >> 16));
136 os.write((int)(bits >> 24));
137 os.write((int)(bits >> 32));
138 os.write((int)(bits >> 40));
139 os.write((int)(bits >> 48));
140 os.write((int)(bits >> 56));
141 }
142 }
143 }
144
145 public static double readDoubleData(InputContext ctx, int type) throws IOException {
146 double v;
147
148 switch ((type >> 6) & 0x03) {
149 case 3:
150 v = Double.NaN;
151 break;
152 case 2:
153 v = ctx.getSharedContext().getCodecRegistry().getLongCodec().readVariableLong(ctx);
154 break;
155 case 1:
156 int i = ctx.safeRead();
157 i |= ctx.safeRead() << 8;
158 i |= ctx.safeRead() << 16;
159 i |= ctx.safeRead() << 24;
160 v = Float.intBitsToFloat(i);
161 break;
162 default: // case 0:
163 long l = ctx.safeRead();
164 l |= ((long)ctx.safeRead()) << 8;
165 l |= ((long)ctx.safeRead()) << 16;
166 l |= ((long)ctx.safeRead()) << 24;
167 l |= ((long)ctx.safeRead()) << 32;
168 l |= ((long)ctx.safeRead()) << 40;
169 l |= ((long)ctx.safeRead()) << 48;
170 l |= ((long)ctx.safeRead()) << 56;
171 v = Double.longBitsToDouble(l);
172 break;
173 }
174
175 return v;
176 }
177 }