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 }