001 /**
002 * Copyright (C) 2010, Skype Limited
003 *
004 * All intellectual property rights, including but not limited to copyrights,
005 * trademarks and patents, as well as know how and trade secrets contained in,
006 * relating to, or arising from the internet telephony software of
007 * Skype Limited (including its affiliates, "Skype"), including without
008 * limitation this source code, Skype API and related material of such
009 * software proprietary to Skype and/or its licensors ("IP Rights") are and
010 * shall remain the exclusive property of Skype and/or its licensors.
011 * The recipient hereby acknowledges and agrees that any unauthorized use of
012 * the IP Rights is a violation of intellectual property laws.
013 *
014 * Skype reserves all rights and may take legal action against infringers of
015 * IP Rights.
016 *
017 * The recipient agrees not to remove, obscure, make illegible or alter any
018 * notices or indications of the IP Rights and/or Skype's rights and
019 * ownership thereof.
020 */
021
022 package com.skype.ipc;
023
024 import java.io.IOException;
025 import java.util.HashMap;
026 import java.util.Collection;
027
028 import com.skype.util.Log;
029
030 public class GetPropertyResponse extends AbstractDecoder
031 {
032 private static final String TAG="GetPropertyResponse";
033
034 private static final class NotFound {}
035 private class PropertyResponseKey
036 {
037 public int oid;
038 public int propid;
039 public PropertyResponseKey() {};
040 public PropertyResponseKey(int inoid,int inpropid)
041 {
042 oid=inoid;
043 propid=inpropid;
044 }
045 public int Key()
046 {
047 return (oid*0x10000)+propid;
048 }
049 }
050 private HashMap<Integer,Object> props; // if the Object instance of NotFound then property message was valid but value was not found
051 private Object single_prop;
052
053 private int moid;
054 private boolean invalid;
055 private int single_oid;
056 private int single_propid;
057 private boolean multiresponse;
058
059 // null response object, used for returning an error condition, like when there is no runtime conneciton
060 public GetPropertyResponse()
061 {
062 super(null);
063 invalid = true;
064 multiresponse = false;
065 }
066
067 GetPropertyResponse(Transport in) throws IOException
068 {
069 // G propid modid oid*;
070 // g (moid (oid (N tag | kind tag value)*)*)* z
071
072 super(in);
073 invalid=false;
074 moid=-1;
075 multiresponse=false;
076 PropertyResponseKey currentkey;
077 try {
078 do
079 {
080 if(moid!=-1 && multiresponse==false)
081 {
082 //this is a multiresponse
083 multiresponse=true;
084 props=new HashMap<Integer,Object>();
085 PropertyResponseKey k=new PropertyResponseKey(single_oid,single_propid);
086 props.put(k.Key(), single_prop);
087 }
088 int temp=decodeVaruint();
089 if(moid!=temp && moid!=-1)
090 {
091 throw new IOException("Multiple moids in single GetPropertyResponse are not supported! (previous="+moid+", new="+temp+").");
092 }
093 moid=temp;
094 currentkey=new PropertyResponseKey();
095 currentkey.oid=decodeVaruint();
096 }
097 while(DecodeNextParm(currentkey)==true);
098 } catch (IOException e) {
099 Log.e(TAG,"IOException while decoding property response="+e.getMessage());
100 invalid=true;
101 }
102 }
103 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
104 //
105 // ACCESSORIES FOR GETPROPERTY RESPONSES
106 //
107 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
108
109 public int getPropId()
110 {
111 if(isMultiresponse())
112 {
113 Log.e(TAG,"getPropId() called for a multiresponse. Returnvalue will be nonsense.");
114 return 0;
115 }
116 return single_propid;
117 }
118 public int getOid()
119 {
120 if(isMultiresponse())
121 {
122 Log.e(TAG,"getOid() called for a multiresponse. Returnvalue will be nonsense.");
123 return 0;
124 }
125 return single_oid;
126 }
127 public String GetAsString()
128 {
129 Object retval=validateAndGetSingleParm();
130 if(retval==null)
131 {
132 Log.d(TAG,"Missing String value. Defaulting to \"\".");
133 return new String("");
134 }
135 if(retval instanceof NotFound)
136 {
137 Log.d(TAG,"String value not found 'N'.");
138 return null;
139 }
140 return (String)retval;
141 }
142 public byte[] GetAsBinary()
143 {
144
145 Object retval=validateAndGetSingleParm();
146 if(retval==null || retval instanceof NotFound)
147 {
148 Log.d(TAG,"Missing or not found binary value. Defaulting to null.");
149 return null;
150 }
151 return (byte[])retval;
152 }
153 public Integer GetAsInt()
154 {
155 Object retval=validateAndGetSingleParm();
156 if(retval==null)
157 {
158 // default value of an omitted boolean value
159 Log.d(TAG,"Missing integer value. Defaulting to 0.");
160 return 0;
161 }
162 if(retval instanceof NotFound)
163 {
164 Log.d(TAG,"Integer value not found 'N'.");
165 return null;
166 }
167 return (Integer)retval;
168 }
169 public Boolean GetAsBoolean()
170 {
171 Object retval=validateAndGetSingleParm();
172 if(retval==null)
173 {
174 // default value of an omitted boolean value
175 Log.d(TAG,"Missing boolean value. Defaulting to false.");
176 return false;
177 }
178 if(retval instanceof NotFound)
179 {
180 Log.d(TAG,"Boolean value not found 'N'.");
181 return null;
182 }
183 return (((Number)retval).intValue()!=0);
184 }
185 // returns true, if there is more occurrences of the last piece of data read. I.e. if GetAsInt
186 public boolean HasMore()
187 {
188 if(single_prop!=null)
189 {
190 if(single_prop instanceof ResponseListElement)
191 {
192 return ((ResponseListElement)single_prop).HasMore();
193 }
194 }
195 return false;
196 }
197
198 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
199 //
200 // ACCESSORIES FOR MULTIGETPROPERTY RESPONSES
201 //
202 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
203
204 public String GetAsString(int oid,int propid)
205 {
206 Object retval=validateAndGetMultiParm(oid,propid);
207 if(retval==null)
208 {
209 Log.d(TAG,"Missing String value for oid="+oid+", propid="+propid+". Defaulting to \"\".");
210 return new String("");
211 }
212 if(retval instanceof NotFound)
213 {
214 Log.d(TAG,"String value not found 'N'.");
215 return null;
216 }
217 return (String)retval;
218 }
219 public byte[] GetAsBinary(int oid,int propid)
220 {
221 Object retval=validateAndGetMultiParm(oid,propid);
222 if(retval==null || retval instanceof NotFound)
223 {
224 Log.d(TAG,"Missing binary value for oid="+oid+", propid="+propid+". Defaulting to null.");
225 return null;
226 }
227 return (byte[])retval;
228 }
229 public Integer GetAsInt(int oid,int propid)
230 {
231 Object retval=validateAndGetMultiParm(oid,propid);
232 if(retval==null)
233 {
234 Log.d(TAG,"Missing integer value for oid="+oid+", propid="+propid+". Defaulting to 0.");
235 return 0;
236 }
237 if(retval instanceof NotFound)
238 {
239 Log.d(TAG,"Integer value not found 'N'.");
240 return null;
241 }
242 return (Integer)retval;
243 }
244
245 public Boolean GetAsBoolean(int oid,int propid)
246 {
247 Object retval=validateAndGetMultiParm(oid,propid);
248 if(retval==null)
249 {
250 Log.d(TAG,"Missing boolean value for oid="+oid+", propid="+propid+". Defaulting to false.");
251 return false;
252 }
253 if(retval instanceof NotFound)
254 {
255 Log.d(TAG,"Boolean value not found 'N'.");
256 return null;
257 }
258 return (((Number)retval).intValue()!=0);
259 }
260
261 // returns true, if there is more occurrences of the last piece of data read. I.e. if GetAsInt
262 public boolean HasMore(int oid,int propid)
263 {
264 PropertyResponseKey k=new PropertyResponseKey(oid,propid);
265 Object o=props.get(k);
266 if(o!=null)
267 {
268 if(o instanceof ResponseListElement)
269 {
270 return ((ResponseListElement)o).HasMore();
271 }
272 }
273 return false;
274 }
275
276 /** retrieves HashMap<Integer,Object> of multiresponse values for a given oid*/
277 public HashMap<Integer, Object> GetAsMap(int oid, Collection<Integer> propId)
278 {
279 if(!multiresponse)
280 {
281 Log.e(TAG,"GetAsMap called for a singleresponse. Returnvalue will be nonsense.");
282 return null;
283 }
284
285 HashMap<Integer, Object> map = new HashMap<Integer, Object>();
286 for (Integer id : propId) {
287 Object retval=validateAndGetMultiParm(oid, id);
288 if ((retval == null) || (retval instanceof NotFound)) {
289 Log.d(TAG, "Missing value for oid=" + oid + ", propid=" + id + ". Not added.");
290 }
291 else {
292 map.put(id, retval);
293 }
294 }
295 return map;
296 }
297
298
299 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
300 //
301 // COMMON ACCESSORIES
302 //
303 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
304
305 public boolean isMultiresponse()
306 {
307 return(multiresponse);
308 }
309
310 public boolean isValid()
311 {
312 return (!invalid);
313 }
314
315 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
316 //
317 // PRIVATE
318 //
319 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
320
321 private Object validateAndGetSingleParm()
322 {
323 if(invalid)
324 {
325 Log.e(TAG,"ValidateAndGetSingleParm called for an invalid property response message. Returnvalue will be nonsense.");
326 return null;
327 }
328 if(multiresponse)
329 {
330 Log.e(TAG,"validateAndGetSingleParm called for a multiresponse. Returnvalue will be nonsense.");
331 return null;
332 }
333 if(single_prop==null)
334 {
335 return null;
336 }
337 if(single_prop instanceof ResponseListElement)
338 {
339 Object oelement=((ResponseListElement)single_prop).GetNext();
340 if(oelement==null)
341 {
342 Log.e(TAG,"validateAndGetSingleParm() called for ResponseListElement while hasMore="+((ResponseListElement)single_prop).HasMore()+". Returnvalue will be nonsense.");
343 }
344 return oelement;
345 }
346 return single_prop;
347 }
348
349 private Object validateAndGetMultiParm(int oid,int propid)
350 {
351 PropertyResponseKey k=new PropertyResponseKey(oid,propid);
352 if(invalid)
353 {
354 Log.e(TAG,"ValidateAndGetMultiParm called for an invalid property response message. Returnvalue will be nonsense.");
355 return null;
356 }
357 if(!multiresponse)
358 {
359 Log.e(TAG,"validateAndGetMultiParm called for a singleresponse. Returnvalue will be nonsense.");
360 return null;
361 }
362 Object o=props.get(k.Key());
363 if(o==null)
364 {
365 return null;
366 }
367 if(o instanceof ResponseListElement)
368 {
369 Object oelement=((ResponseListElement)o).GetNext();
370 if(oelement==null)
371 {
372 Log.e(TAG,"validateAndGetMultiParm() called for ResponseListElement while hasMore="+((ResponseListElement)o).HasMore()+". Returnvalue will be nonsense.");
373 }
374 return oelement;
375 }
376 return o;
377 }
378
379 private boolean HasNext() throws IOException
380 {
381 int kind=ioTransport.peek();
382 while(kind==']')
383 {
384 ioTransport.read();
385 kind=ioTransport.peek();
386 }
387 if(kind=='z')
388 {
389 ioTransport.read();
390 return false;
391 }
392 if(kind==',')
393 {
394 ioTransport.read();
395 return true;
396 }
397 invalid=true;
398 return false;
399 }
400
401 private boolean DecodeNextParm(PropertyResponseKey key) throws IOException
402 {
403 int kind=ioTransport.read();
404 while(kind==']')
405 {
406 kind=ioTransport.read();
407 }
408 if(kind=='N')
409 {
410 key.propid=decodeVaruint();
411 if(multiresponse)
412 {
413 props.put(key.Key(),new NotFound());
414 }
415 else
416 {
417 single_propid=key.propid;
418 single_oid=key.oid;
419 single_prop=new NotFound();
420 }
421 }
422 else
423 {
424 key.propid=decodeVaruint();
425 if(multiresponse)
426 {
427 props.put(key.Key(), decodeOneOfKind(kind));
428 }
429 else
430 {
431 single_propid=key.propid;
432 single_oid=key.oid;
433 single_prop=decodeOneOfKind(kind);
434 }
435 }
436 //Log.d(TAG,"Decoded propid="+key.propid+", oid="+key.oid+"kind='"+(char)kind+"'.");
437 return HasNext();
438 }
439 }