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