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.InputContext;
028    import org.granite.messaging.jmf.OutputContext;
029    
030    /**
031     * @author Franck WOLFF
032     */
033    public 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    }