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 021package org.granite.messaging.jmf.codec.std.impl; 022 023import java.io.IOException; 024import java.io.OutputStream; 025 026import org.granite.messaging.jmf.DumpContext; 027import org.granite.messaging.jmf.InputContext; 028import org.granite.messaging.jmf.OutputContext; 029import org.granite.messaging.jmf.codec.std.LongCodec; 030 031/** 032 * @author Franck WOLFF 033 */ 034public class LongCodecImpl extends AbstractStandardCodec<Long> implements LongCodec { 035 036 public int getObjectType() { 037 return JMF_LONG_OBJECT; 038 } 039 040 public Class<?> getObjectClass() { 041 return Long.class; 042 } 043 044 public int getPrimitiveType() { 045 return JMF_LONG; 046 } 047 048 public Class<?> getPrimitiveClass() { 049 return Long.TYPE; 050 } 051 052 public void encode(OutputContext ctx, Long v) throws IOException { 053 writeLongData(ctx, JMF_LONG_OBJECT, v.longValue()); 054 } 055 056 public Long decode(InputContext ctx, int parameterizedJmfType) throws IOException { 057 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType); 058 059 if (jmfType != JMF_LONG_OBJECT) 060 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType); 061 062 return Long.valueOf(readLongData(ctx, parameterizedJmfType)); 063 } 064 065 public void encodePrimitive(OutputContext ctx, long v) throws IOException { 066 writeLongData(ctx, JMF_LONG, v); 067 } 068 069 public long decodePrimitive(InputContext ctx) throws IOException { 070 int parameterizedJmfType = ctx.safeRead(); 071 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType); 072 073 if (jmfType != JMF_LONG) 074 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType); 075 076 return readLongData(ctx, parameterizedJmfType); 077 } 078 079 public void dump(DumpContext ctx, int parameterizedJmfType) throws IOException { 080 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType); 081 082 switch (jmfType) { 083 case JMF_LONG: 084 ctx.indentPrintLn("long: " + readLongData(ctx, parameterizedJmfType)); 085 break; 086 case JMF_LONG_OBJECT: 087 ctx.indentPrintLn(Long.class.getName() + ": " + Long.valueOf(readLongData(ctx, parameterizedJmfType))); 088 break; 089 default: 090 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType); 091 } 092 } 093 094 protected void writeLongData(OutputContext ctx, int jmfType, long v) throws IOException { 095 int l = 7; // --> Long.MIN_VALUE 096 int s = 0x00; 097 if (v != Long.MIN_VALUE) { 098 if (v < 0) { 099 s = 0x80; 100 v = -v; 101 } 102 l = lenghtOfAbsoluteLong(v); 103 } 104 105 final OutputStream os = ctx.getOutputStream(); 106 107 os.write(s | (l << 4) | jmfType); 108 switch (l) { 109 case 7: 110 os.write((int)(v >> 56)); 111 case 6: 112 os.write((int)(v >> 48)); 113 case 5: 114 os.write((int)(v >> 40)); 115 case 4: 116 os.write((int)(v >> 32)); 117 case 3: 118 os.write((int)(v >> 24)); 119 case 2: 120 os.write((int)(v >> 16)); 121 case 1: 122 os.write((int)(v >> 8)); 123 case 0: 124 os.write((int)v); 125 break; 126 } 127 } 128 129 protected int lenghtOfAbsoluteLong(long v) { 130 if (v <= 0x00000000FFFFFFFFL) { 131 if (v <= 0x000000000000FFFFL) 132 return (v <= 0x00000000000000FFL ? 0 : 1); 133 return (v <= 0x0000000000FFFFFFL ? 2 : 3); 134 } 135 136 if (v <= 0x0000FFFFFFFFFFFFL) 137 return (v <= 0x000000FFFFFFFFFFL ? 4 : 5); 138 return (v <= 0x00FFFFFFFFFFFFFFL ? 6 : 7); 139 } 140 141 protected long readLongData(InputContext ctx, int parameterizedJmfType) throws IOException { 142 long v = 0; 143 144 switch ((parameterizedJmfType >> 4) & 0x07) { 145 case 7: 146 v |= ((long)ctx.safeRead()) << 56; 147 case 6: 148 v |= ((long)ctx.safeRead()) << 48; 149 case 5: 150 v |= ((long)ctx.safeRead()) << 40; 151 case 4: 152 v |= ((long)ctx.safeRead()) << 32; 153 case 3: 154 v |= ((long)ctx.safeRead()) << 24; 155 case 2: 156 v |= ((long)ctx.safeRead()) << 16; 157 case 1: 158 v |= ((long)ctx.safeRead()) << 8; 159 case 0: 160 v |= ctx.safeRead(); 161 } 162 163 if ((parameterizedJmfType & 0x80) != 0) 164 v = -v; 165 166 return v; 167 } 168 169 public void writeVariableLong(OutputContext ctx, long v) throws IOException { 170 171 final OutputStream os = ctx.getOutputStream(); 172 173 if (v == Long.MIN_VALUE) 174 os.write(0x80); 175 else { 176 int sign = 0x00; 177 if (v < 0) { 178 sign = 0x80; 179 v = -v; 180 } 181 182 int bytesCount = lengthOfVariableAbsoluteLong(v); 183 v -= deltaForVariableAbsoluteLongLength(bytesCount); 184 185 switch (bytesCount) { 186 case 0: 187 os.write(sign | (int)v); 188 break; 189 case 1: case 2: case 3: case 4: case 5: case 6: case 7: 190 os.write(sign | 0x40 | (int)(v >> (bytesCount * 7))); 191 for (int i = bytesCount - 1; i > 0; i--) 192 os.write(0x80 | (int)(v >> (i * 7))); 193 os.write(0x7F & (int)v); 194 break; 195 case 8: 196 os.write(sign | 0x40 | (int)(v >> 57)); 197 os.write(0x80 | (int)(v >> 50)); 198 os.write(0x80 | (int)(v >> 43)); 199 os.write(0x80 | (int)(v >> 36)); 200 os.write(0x80 | (int)(v >> 29)); 201 os.write(0x80 | (int)(v >> 22)); 202 os.write(0x80 | (int)(v >> 15)); 203 os.write(0x80 | (int)(v >> 8)); 204 os.write((int)v); 205 break; 206 } 207 } 208 } 209 210 public long readVariableLong(InputContext ctx) throws IOException { 211 long v = ctx.safeRead(); 212 213 if (v == 0x80L) 214 v = Long.MIN_VALUE; 215 else { 216 boolean opposite = ((v & 0x80L) != 0); 217 boolean readNext = (v & 0x40L) != 0; 218 219 v &= 0x3FL; 220 221 if (readNext) { 222 int l = 1; 223 for (int i = 1; i <= 7; i++) { 224 long u = ctx.safeRead(); 225 v = (v << 7) | (u & 0x7FL); 226 if ((u & 0x80L) == 0) { 227 readNext = false; 228 break; 229 } 230 l++; 231 } 232 if (readNext) 233 v = (v << 8) | ctx.safeRead(); 234 v += deltaForVariableAbsoluteLongLength(l); 235 } 236 237 if (opposite) 238 v = -v; 239 } 240 241 return v; 242 } 243 244 protected static final long[] VARIABLE_LONG_DELTAS = new long[9]; 245 static { 246 VARIABLE_LONG_DELTAS[0] = 0L; 247 for (int i = 1; i < VARIABLE_LONG_DELTAS.length; i++) 248 VARIABLE_LONG_DELTAS[i] = (VARIABLE_LONG_DELTAS[i-1] << 7) | 0x40L; 249 } 250 251 protected static int lengthOfVariableAbsoluteLong(long abs) { 252 for (int i = 1; i < VARIABLE_LONG_DELTAS.length; i++) { 253 if (abs < VARIABLE_LONG_DELTAS[i]) 254 return (i - 1); 255 } 256 return 8; 257 } 258 259 protected static long deltaForVariableAbsoluteLongLength(int len) { 260 return VARIABLE_LONG_DELTAS[len]; 261 } 262}