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