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