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