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 */
022package org.granite.messaging.jmf.codec.std.impl;
023
024import java.io.IOException;
025import java.io.OutputStream;
026
027import org.granite.messaging.jmf.InputContext;
028import org.granite.messaging.jmf.OutputContext;
029
030/**
031 * @author Franck WOLFF
032 */
033public abstract class AbstractIntegerStringCodec<T> extends AbstractStandardCodec<T> {
034        
035        protected void writeIntData(OutputContext ctx, IntegerComponents ics) throws IOException {
036                int v = ics.value;
037                
038                final OutputStream os = ctx.getOutputStream();
039                
040                switch (ics.length) {
041                case 3:
042                        os.write(v >> 24);
043                case 2:
044                        os.write(v >> 16);
045                case 1:
046                        os.write(v >> 8);
047                case 0:
048                        os.write(v);
049                        break;
050                }
051        }
052        
053        protected int readIntData(InputContext ctx, int length, boolean opposite) throws IOException {
054                int v = 0;
055                
056                switch (length) {
057                case 3:
058                        v |= ctx.safeRead() << 24;
059                case 2:
060                        v |= ctx.safeRead() << 16;
061                case 1:
062                        v |= ctx.safeRead() << 8;
063                case 0:
064                        v |= ctx.safeRead();
065                }
066                
067                if (opposite)
068                        v = -v;
069                
070                return v;
071        }
072
073        protected IntegerComponents intComponents(int v) {
074                int s = 0;
075                int l = 3; // --> Integer.MIN_VALUE
076                if (v != Integer.MIN_VALUE) {
077                        if (v < 0) {
078                                s = 1;
079                                v = -v;
080                        }
081                        if (v <= 0xFFFF)
082                                l = (v <= 0xFF ? 0 : 1);
083                        else
084                                l = (v <= 0xFFFFFF ? 2 : 3);
085                }
086                return new IntegerComponents(s, l, v);
087        }
088        
089        protected void writeString(OutputContext ctx, String v, StringTypeHandler handler) throws IOException {
090                if (v == null)
091                        throw new NullPointerException("String value cannot be null");
092                
093                final OutputStream os = ctx.getOutputStream();
094                
095                int indexOfStoredString = ctx.indexOfStoredStrings(v);
096                
097                if (indexOfStoredString >= 0) {
098                        IntegerComponents ics = intComponents(indexOfStoredString);
099                        os.write(handler.type(ics, true));
100                        writeIntData(ctx, ics);
101                }
102                else {
103                        ctx.addToStoredStrings(v);
104                        
105                        if (v.length() == 0) {
106                                os.write(handler.type(IntegerComponents.ZERO, false));
107                                os.write(0);
108                        }
109                        else {
110                                final byte[] bytes = v.getBytes(UTF8);
111                                final int length = bytes.length;
112        
113                                IntegerComponents ics = intComponents(length);
114                                os.write(handler.type(ics, false));
115                                writeIntData(ctx, ics);
116        
117                                os.write(bytes);
118                        }
119                }
120        }
121        
122        protected String readString(InputContext ctx, int parameterizedJmfType, StringTypeHandler handler) throws IOException {
123                int indexOrLength = readIntData(ctx, handler.indexOrLengthBytesCount(parameterizedJmfType), false);
124                return readString(ctx, parameterizedJmfType, indexOrLength, handler);
125        }
126        
127        protected String readString(InputContext ctx, int parameterizedJmfType, int indexOrLength, StringTypeHandler handler) throws IOException {
128                if (handler.isReference(parameterizedJmfType))
129                        return ctx.getSharedString(indexOrLength);
130
131                byte[] bytes = new byte[indexOrLength];
132                ctx.safeReadFully(bytes);
133                String s = new String(bytes, UTF8);
134                
135                ctx.addSharedString(s);
136                
137                return s;
138        }
139        
140        protected static class IntegerComponents {
141                
142                public static final IntegerComponents ZERO = new IntegerComponents(0, 0, 0);
143                
144                public final int sign;
145                public final int length;
146                public final int value;
147
148                public IntegerComponents(int sign, int length, int value) {
149                        this.sign = sign;
150                        this.length = length;
151                        this.value = value;
152                }
153        }
154        
155        protected static interface StringTypeHandler {
156                
157                int type(IntegerComponents ics, boolean reference);
158                int indexOrLengthBytesCount(int parameterizedJmfType);
159                boolean isReference(int parameterizedJmfType);
160        }
161
162        protected static final StringTypeHandler JMF_STRING_TYPE_HANDLER = new StringTypeHandler() {
163
164                public int type(IntegerComponents ics, boolean reference) {
165                        if (reference)
166                                return 0x80 | (ics.length << 5) | JMF_STRING;
167                        return (ics.length << 5) | JMF_STRING;
168                }
169
170                public int indexOrLengthBytesCount(int parameterizedJmfType) {
171                        return (parameterizedJmfType >> 5) & 0x03;
172                }
173
174                public boolean isReference(int parameterizedJmfType) {
175                        return (parameterizedJmfType & 0x80) != 0;
176                }
177        };
178}