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