001 package com.skype.ipc;
002
003 import java.io.IOException;
004
005 public final class EventBuffer implements InputTransporting {
006 private final int MIN_BUFFER_SIZE = 512;
007
008 public EventBuffer(int listMaxNested, int listMaxElem) {
009 mBuffer = new byte[MIN_BUFFER_SIZE];
010 mBegin = 0;
011 mEnd = 0;
012 mSize = 0;
013 mListMaxNested = listMaxNested;
014 mListMaxElem = listMaxElem;
015 mListDepth = 0;
016 }
017
018 public synchronized boolean isEmpty() {
019 return mSize == 0;
020 }
021
022 //
023 // InputTransporting
024 //
025
026 synchronized public void skipBytes(int numBytes) throws IOException {
027 int n = numBytes;
028 int capacity = mBuffer.length;
029 assert(n <= mSize);
030 if ((mBegin+n) > capacity) {
031 int len = capacity - mBegin;
032 n -= len;
033 mBegin = 0;
034 }
035 mBegin = (mBegin+n)&(capacity-1);
036 mSize -= numBytes;
037 // shrink?
038 if (mSize < MIN_BUFFER_SIZE && capacity > MIN_BUFFER_SIZE)
039 resize(MIN_BUFFER_SIZE);
040 // return numBytes;
041 }
042
043 synchronized public void readBytes(byte [] dest, int offset, int numBytes) throws IOException {
044 // one shall not read more than what is available as the payloads are fully buffered
045 // before getting accessible
046 int n = numBytes;
047 int capacity = mBuffer.length;
048 assert(n <= mSize);
049 if ((mBegin+n) > capacity) {
050 int len = capacity - mBegin;
051 System.arraycopy(mBuffer, mBegin, dest, offset, len);
052 mSize -= len;
053 n -= len;
054 offset += len;
055 mBegin = 0;
056 }
057 System.arraycopy(mBuffer, mBegin, dest, offset, n);
058 mBegin = (mBegin+n)&(capacity-1);
059 mSize -= n;
060 // shrink?
061 if (mSize < MIN_BUFFER_SIZE && capacity > MIN_BUFFER_SIZE)
062 resize(MIN_BUFFER_SIZE);
063 }
064
065 synchronized public int readByte() throws IOException {
066 assert(mSize > 0);
067 int capacity = mBuffer.length;
068 int b = mBuffer[mBegin];
069 mBegin = (mBegin+1)&(capacity-1);
070 mSize--;
071 if (mSize < MIN_BUFFER_SIZE && capacity > MIN_BUFFER_SIZE)
072 resize(MIN_BUFFER_SIZE);
073 return b;
074 }
075
076 public void readBytes(byte[] dest) throws IOException {
077 readBytes(dest, 0, dest.length);
078 }
079
080 private void grow(int minSize) {
081 int capacity = mBuffer.length+mBuffer.length;
082 while (capacity < minSize) {
083 capacity = capacity + capacity;
084 }
085 resize(capacity);
086 }
087
088 private void resize(int capacity) {
089 byte[] newBuffer = new byte[capacity];
090 if (mSize > 0) {
091 if (mBegin < mEnd) {
092 System.arraycopy(mBuffer, mBegin, newBuffer, 0, mSize);
093 } else {
094 System.arraycopy(mBuffer, mBegin, newBuffer, 0, mBuffer.length-mBegin);
095 System.arraycopy(mBuffer, 0, newBuffer, mBuffer.length-mBegin, mEnd);
096 }
097 }
098 mBegin = 0;
099 mEnd = mSize;
100 mBuffer = newBuffer;
101 }
102
103 private int putByte(int b) {
104 if (mSize == mBuffer.length)
105 grow(mBuffer.length+1);
106 mBuffer[mEnd++] = (byte) b;
107 mEnd &= mBuffer.length-1;
108 mSize++;
109 return b;
110 }
111
112 private void putBytes(int n, InputTransporting reader) throws IOException {
113 if ((mSize+n) > mBuffer.length)
114 grow(mSize+n);
115 if ((mEnd+n) > mBuffer.length) {
116 int m = mBuffer.length - mEnd;
117 reader.readBytes(mBuffer, mEnd, m);
118 mEnd = 0;
119 mSize += m;
120 n -= m;
121 }
122 reader.readBytes(mBuffer, mEnd, n);
123 mEnd += n;
124 if (mEnd == mBuffer.length) mEnd = 0;
125 mSize += n;
126 }
127
128 private int bufferUint(InputTransporting transport) throws IOException {
129 int shift = 0;
130 int result = 0;
131 while (true) {
132 int value = putByte(transport.readByte()) & 0xFF;
133 result = result | ((value & 0x7f) << shift);
134 shift = shift + 7;
135 if ((value & 0x80) == 0)
136 break;
137 }
138 return result;
139 }
140
141 private long bufferUint64(InputTransporting transport) throws IOException {
142 int shift = 0;
143 long result = 0;
144 while (true) {
145 int value = putByte(transport.readByte()) & 0xFF;
146 result = result | ((value & 0x7f) << shift);
147 shift = shift + 7;
148 if ((value & 0x80) == 0)
149 break;
150 }
151 return result;
152 }
153
154 private void bufferValue(int kind, InputTransporting transport) throws IOException {
155 switch (kind) {
156 case 'i': case 'O': case 'u': case 'e': case 'b':
157 bufferUint(transport);
158 return;
159 case 'T': case 'F': case 'N':
160 return;
161 case 'U':
162 bufferUint64(transport);
163 return;
164 case 'S': case 'X': case 'f': case 'B':
165 putBytes(bufferUint(transport), transport);
166 return;
167 case '[': {
168 if (mListDepth++ > mListMaxNested) throw new ProtocolException("listDepth");
169 int elemKind = putByte(transport.readByte());
170 int numElem = 0;
171 while (elemKind != ']') {
172 bufferValue(elemKind, transport);
173 if (numElem++ > mListMaxElem) throw new ProtocolException("list too large");
174 }
175 mListDepth--;
176 return;
177 }
178 default:
179 throw new ProtocolException("unknown kind");
180 }
181 }
182
183 public synchronized void bufferEvent(InputTransporting transport) throws IOException {
184 putByte('Z');
185 putByte('E');
186 bufferUint(transport); // moduleId
187 bufferUint(transport); // eventId
188 do {
189 int kind = putByte(transport.readByte());
190 if (kind == 'z') return;
191 bufferUint(transport);
192 bufferValue(kind, transport);
193 } while (true);
194 }
195
196 public synchronized void bufferChange(InputTransporting transport) throws IOException {
197 putByte('Z');
198 putByte('C');
199 bufferUint(transport); // moduleId
200 bufferUint(transport); // oid
201 boolean valueExpected = true;
202 do {
203 int sign = putByte(transport.readByte()); // next property?
204 if (sign == ']') { // end of property
205 if (valueExpected) {
206 throw new ProtocolException("expecting a value");
207 }
208 sign = putByte(transport.readByte());
209 if (sign == ']') { // end objects
210 sign = putByte(transport.readByte());
211 if (sign == ']') {
212 sign = putByte(transport.readByte());
213 if (sign != 'z') throw new ProtocolException("change shall terminate");
214 return;
215 } else if (sign == ',') { // next module
216 bufferUint(transport); // moduleId
217 bufferUint(transport); // oid
218 valueExpected = true;
219 } else {
220 throw new ProtocolException("");
221 }
222 } else if (sign == ',') { // next object
223 bufferUint(transport); // oid
224 valueExpected = true;
225 } else {
226 throw new ProtocolException("");
227 }
228 } else { // next property
229 bufferUint(transport);
230 bufferValue(sign, transport);
231 valueExpected = false;
232 }
233 } while (true);
234 }
235
236 public void close() throws IOException {
237 mSize = 0;
238 }
239
240 byte[] mBuffer;
241 int mBegin;
242 int mEnd;
243 int mSize;
244 int mListDepth;
245 int mListMaxNested;
246 int mListMaxElem;
247 }
248