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.IntegerCodec;
030    
031    /**
032     * @author Franck WOLFF
033     */
034    public 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    }