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