001
014
015 package com.liferay.portal.kernel.io;
016
017 import com.liferay.portal.kernel.util.CharBufferPool;
018 import com.liferay.portal.kernel.util.ClassLoaderPool;
019 import com.liferay.portal.kernel.util.ClassResolverUtil;
020
021 import java.io.IOException;
022 import java.io.InputStream;
023 import java.io.ObjectInputStream;
024 import java.io.Serializable;
025
026 import java.nio.ByteBuffer;
027
028
032 public class Deserializer {
033
034 public Deserializer(ByteBuffer byteBuffer) {
035 buffer = byteBuffer.array();
036 index = byteBuffer.arrayOffset();
037 limit = index + byteBuffer.remaining();
038 }
039
040 public boolean readBoolean() {
041 detectBufferUnderflow(1);
042
043 return BigEndianCodec.getBoolean(buffer, index++);
044 }
045
046 public byte readByte() {
047 detectBufferUnderflow(1);
048
049 return buffer[index++];
050 }
051
052 public char readChar() {
053 detectBufferUnderflow(2);
054
055 char c = BigEndianCodec.getChar(buffer, index);
056
057 index += 2;
058
059 return c;
060 }
061
062 public double readDouble() {
063 detectBufferUnderflow(8);
064
065 double d = BigEndianCodec.getDouble(buffer, index);
066
067 index += 8;
068
069 return d;
070 }
071
072 public float readFloat() {
073 detectBufferUnderflow(4);
074
075 float f = BigEndianCodec.getFloat(buffer, index);
076
077 index += 4;
078
079 return f;
080 }
081
082 public int readInt() {
083 detectBufferUnderflow(4);
084
085 int i = BigEndianCodec.getInt(buffer, index);
086
087 index += 4;
088
089 return i;
090 }
091
092 public long readLong() {
093 detectBufferUnderflow(8);
094
095 long l = BigEndianCodec.getLong(buffer, index);
096
097 index += 8;
098
099 return l;
100 }
101
102 public <T extends Serializable> T readObject()
103 throws ClassNotFoundException {
104
105 byte tcByte = buffer[index++];
106
107 switch (tcByte) {
108 case SerializationConstants.TC_BOOLEAN:
109 return (T)Boolean.valueOf(readBoolean());
110
111 case SerializationConstants.TC_BYTE:
112 return (T)Byte.valueOf(readByte());
113
114 case SerializationConstants.TC_CHARACTER:
115 return (T)Character.valueOf(readChar());
116
117 case SerializationConstants.TC_CLASS:
118 String contextName = readString();
119 String className = readString();
120
121 ClassLoader classLoader = ClassLoaderPool.getClassLoader(
122 contextName);
123
124 return (T)ClassResolverUtil.resolve(className, classLoader);
125
126 case SerializationConstants.TC_DOUBLE:
127 return (T)Double.valueOf(readDouble());
128
129 case SerializationConstants.TC_FLOAT:
130 return (T)Float.valueOf(readFloat());
131
132 case SerializationConstants.TC_INTEGER:
133 return (T)Integer.valueOf(readInt());
134
135 case SerializationConstants.TC_LONG:
136 return (T)Long.valueOf(readLong());
137
138 case SerializationConstants.TC_NULL:
139 return null;
140
141 case SerializationConstants.TC_SHORT:
142 return (T)Short.valueOf(readShort());
143
144 case SerializationConstants.TC_STRING:
145 return (T)readString();
146
147 case SerializationConstants.TC_OBJECT:
148 try {
149 ObjectInputStream objectInpputStream =
150 new AnnotatedObjectInputStream(new BufferInputStream());
151
152 T t = (T)objectInpputStream.readObject();
153
154 objectInpputStream.close();
155
156 return t;
157 }
158 catch (IOException ioe) {
159 throw new RuntimeException(ioe);
160 }
161
162 default :
163 throw new IllegalStateException("Unkown TC code " + tcByte);
164 }
165 }
166
167 public short readShort() {
168 detectBufferUnderflow(2);
169
170 short s = BigEndianCodec.getShort(buffer, index);
171
172 index += 2;
173
174 return s;
175 }
176
177 public String readString() {
178 detectBufferUnderflow(5);
179
180 boolean asciiCode = BigEndianCodec.getBoolean(buffer, index++);
181
182 int length = BigEndianCodec.getInt(buffer, index);
183
184 index += 4;
185
186 if (asciiCode) {
187 detectBufferUnderflow(length);
188
189 char[] chars = CharBufferPool.borrow(length);
190
191 for (int i = 0; i < length; i++) {
192 chars[i] = (char)buffer[index++];
193 }
194
195 return new String(chars, 0, length);
196 }
197 else {
198 detectBufferUnderflow(length * 2);
199
200 char[] chars = CharBufferPool.borrow(length);
201
202 for (int i = 0; i < length; i++) {
203 chars[i] = BigEndianCodec.getChar(buffer, index);
204
205 index += 2;
206 }
207
208 return new String(chars, 0, length);
209 }
210 }
211
212
215 protected final void detectBufferUnderflow(int availableBytes) {
216 if ((index + availableBytes) > limit) {
217 throw new IllegalStateException("Buffer underflow");
218 }
219 }
220
221 protected byte[] buffer;
222 protected int index;
223 protected int limit;
224
225 protected class BufferInputStream extends InputStream {
226
227 @Override
228 public int read() {
229 return buffer[index++];
230 }
231
232 @Override
233 public int read(byte[] bytes) {
234 return read(bytes, 0, bytes.length);
235 }
236
237 @Override
238 public int read(byte[] bytes, int offset, int length) {
239 int remain = limit - index;
240
241 if (remain < length) {
242 length = remain;
243 }
244
245 System.arraycopy(buffer, index, bytes, offset, length);
246
247 index += length;
248
249 return length;
250 }
251
252 }
253
254 }