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.IntegerCodec; 030 031/** 032 * @author Franck WOLFF 033 */ 034public class IntegerCodecImpl extends AbstractIntegerStringCodec<Integer> implements IntegerCodec { 035 036 public int getObjectType() { 037 return JMF_INTEGER_OBJECT; 038 } 039 040 public Class<?> getObjectClass() { 041 return Integer.class; 042 } 043 044 public int getPrimitiveType() { 045 return JMF_INTEGER; 046 } 047 048 public Class<?> getPrimitiveClass() { 049 return Integer.TYPE; 050 } 051 052 public void encode(OutputContext ctx, Integer v) throws IOException { 053 writeIntData(ctx, JMF_INTEGER_OBJECT, v.intValue()); 054 } 055 056 public Integer decode(InputContext ctx, int parameterizedJmfType) throws IOException { 057 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType); 058 059 if (jmfType != JMF_INTEGER_OBJECT) 060 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType); 061 062 return Integer.valueOf(readIntData(ctx, parameterizedJmfType)); 063 } 064 065 public void encodePrimitive(OutputContext ctx, int v) throws IOException { 066 writeIntData(ctx, JMF_INTEGER, v); 067 } 068 069 public int decodePrimitive(InputContext ctx) throws IOException { 070 int parameterizedJmfType = ctx.safeRead(); 071 int jmfType = ctx.getSharedContext().getCodecRegistry().extractJmfType(parameterizedJmfType); 072 073 if (jmfType != JMF_INTEGER) 074 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType); 075 076 return readIntData(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_INTEGER: 084 ctx.indentPrintLn("int: " + readIntData(ctx, parameterizedJmfType)); 085 break; 086 case JMF_INTEGER_OBJECT: 087 ctx.indentPrintLn(Integer.class.getName() + ": " + Integer.valueOf(readIntData(ctx, parameterizedJmfType))); 088 break; 089 default: 090 throw newBadTypeJMFEncodingException(jmfType, parameterizedJmfType); 091 } 092 } 093 094 protected void writeIntData(OutputContext ctx, int jmfType, int v) throws IOException { 095 IntegerComponents ics = intComponents(v); 096 ctx.getOutputStream().write((ics.sign << 7) | (ics.length << 5) | jmfType); 097 writeIntData(ctx, ics); 098 } 099 100 protected int readIntData(InputContext ctx, int parameterizedJmfType) throws IOException { 101 return readIntData(ctx, (parameterizedJmfType >> 5) & 0x03, (parameterizedJmfType & 0x80) != 0); 102 } 103 104 public void writeVariableInt(OutputContext ctx, int v) throws IOException { 105 106 final OutputStream os = ctx.getOutputStream(); 107 108 if (v == Integer.MIN_VALUE) 109 os.write(0x80); // negative 0. 110 else { 111 int sign = 0x00; 112 if (v < 0) { 113 sign = 0x80; 114 v = -v; 115 } 116 117 int bytesCount = lengthOfVariableAbsoluteInt(v); 118 v -= deltaForVariableAbsoluteIntLength(bytesCount); 119 120 switch (bytesCount) { 121 case 0: 122 os.write(sign | v); 123 break; 124 case 1: case 2: case 3: 125 os.write(sign | 0x40 | (v >> (bytesCount * 7))); 126 for (int i = bytesCount - 1; i > 0; i--) 127 os.write(0x80 | (v >> (i * 7))); 128 os.write(0x7F & v); 129 break; 130 case 4: 131 os.write(sign | 0x40 | (v >> 29)); 132 os.write(0x80 | (v >> 22)); 133 os.write(0x80 | (v >> 15)); 134 os.write(0x80 | (v >> 8)); 135 os.write(v); 136 break; 137 } 138 } 139 } 140 141 public int readVariableInt(InputContext ctx) throws IOException { 142 int v = ctx.safeRead(); 143 144 if (v == 0x80) 145 v = Integer.MIN_VALUE; 146 else { 147 boolean opposite = ((v & 0x80) != 0); 148 boolean readNext = (v & 0x40) != 0; 149 150 v &= 0x3F; 151 152 if (readNext) { 153 int l = 1; 154 for (int i = 1; i <= 3; i++) { 155 int u = ctx.safeRead(); 156 v = (v << 7) | (u & 0x7F); 157 if ((u & 0x80) == 0) { 158 readNext = false; 159 break; 160 } 161 l++; 162 } 163 if (readNext) 164 v = (v << 8) | ctx.safeRead(); 165 v += deltaForVariableAbsoluteIntLength(l); 166 } 167 168 if (opposite) 169 v = -v; 170 } 171 172 return v; 173 } 174 175 protected static final int[] VARIABLE_INT_DELTAS = new int[5]; 176 static { 177 VARIABLE_INT_DELTAS[0] = 0; 178 for (int i = 1; i < VARIABLE_INT_DELTAS.length; i++) 179 VARIABLE_INT_DELTAS[i] = (VARIABLE_INT_DELTAS[i-1] << 7) | 0x40; 180 } 181 182 protected static int lengthOfVariableAbsoluteInt(int abs) { 183 for (int i = 1; i < VARIABLE_INT_DELTAS.length; i++) { 184 if (abs < VARIABLE_INT_DELTAS[i]) 185 return (i - 1); 186 } 187 return 4; 188 } 189 190 protected static int deltaForVariableAbsoluteIntLength(int len) { 191 return VARIABLE_INT_DELTAS[len]; 192 } 193}