corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Collections.Generic;
29 using System.Reflection;
30 using System.Text;
31  
32 namespace OpenMetaverse.Packets
33 {
34  
35 public static class PacketDecoder
36 {
37 /// <summary>
38 /// A custom decoder callback
39 /// </summary>
40 /// <param name="fieldName">The key of the object</param>
41 /// <param name="fieldData">the data to decode</param>
42 /// <returns>A string represending the fieldData</returns>
43 public delegate string CustomPacketDecoder(string fieldName, object fieldData);
44  
45 private static Dictionary<string, List<CustomPacketDecoder>> Callbacks = new Dictionary<string, List<CustomPacketDecoder>>();
46  
47  
48 static PacketDecoder()
49 {
50 AddCallback("Color", DecodeColorField);
51 AddCallback("TextColor", DecodeColorField);
52 AddCallback("Timestamp", DecodeTimeStamp);
53 AddCallback("EstateCovenantReply.Data.CovenantTimestamp", DecodeTimeStamp);
54 AddCallback("CreationDate", DecodeTimeStamp);
55 AddCallback("BinaryBucket", DecodeBinaryBucket);
56 AddCallback("ParcelData.Data", DecodeBinaryToHexString);
57 AddCallback("LayerData.Data", DecodeBinaryToHexString);
58 AddCallback("ImageData.Data", DecodeImageData);
59 AddCallback("TransferData.Data", DecodeBinaryToHexString);
60 AddCallback("ObjectData.TextureEntry", DecodeTextureEntry);
61 AddCallback("ImprovedInstantMessage.MessageBlock.Dialog", DecodeDialog);
62  
63 // Inventory/Permissions
64 AddCallback("BaseMask", DecodePermissionMask);
65 AddCallback("OwnerMask", DecodePermissionMask);
66 AddCallback("EveryoneMask", DecodePermissionMask);
67 AddCallback("NextOwnerMask", DecodePermissionMask);
68 AddCallback("GroupMask", DecodePermissionMask);
69  
70 // FetchInventoryDescendents
71 AddCallback("InventoryData.SortOrder", DecodeInventorySort);
72  
73 AddCallback("WearableType", DecodeWearableType);
74 //
75 AddCallback("InventoryData.Type", DecodeInventoryType);
76 AddCallback("InvType", DecodeInventoryInvType);
77 AddCallback("InventoryData.Flags", DecodeInventoryFlags);
78 // BulkUpdateInventory
79 AddCallback("ItemData.Type", DecodeInventoryType);
80 AddCallback("ItemData.Flags", DecodeInventoryFlags);
81  
82 AddCallback("SaleType", DecodeObjectSaleType);
83  
84 AddCallback("ScriptControlChange.Data.Controls", DecodeScriptControls);
85  
86 AddCallback("RegionFlags", DecodeRegionFlags);
87 AddCallback("SimAccess", DecodeSimAccess);
88 AddCallback("ControlFlags", DecodeControlFlags);
89  
90 // AgentUpdate
91 AddCallback("AgentUpdate.AgentData.State", DecodeAgentState);
92 AddCallback("AgentUpdate.AgentData.Flags", DecodeAgentFlags);
93  
94 // ViewerEffect TypeData
95 AddCallback("ViewerEffect.Effect.TypeData", DecodeViewerEffectTypeData);
96 AddCallback("ViewerEffect.Effect.Type", DecodeViewerEffectType);
97  
98 // Prim/ObjectUpdate decoders
99 AddCallback("ObjectUpdate.ObjectData.PCode", DecodeObjectPCode);
100 AddCallback("ObjectUpdate.ObjectData.Material", DecodeObjectMaterial);
101 AddCallback("ObjectUpdate.ObjectData.ClickAction", DecodeObjectClickAction);
102 AddCallback("ObjectData.UpdateFlags", DecodeObjectUpdateFlags);
103  
104 AddCallback("ObjectUpdate.ObjectData.ObjectData", DecodeObjectData);
105 AddCallback("TextureAnim", DecodeObjectTextureAnim);
106 AddCallback("ObjectUpdate.ObjectData.NameValue", DecodeNameValue);
107 AddCallback("ObjectUpdate.ObjectData.Data", DecodeObjectData);
108  
109 AddCallback("ObjectUpdate.ObjectData.PSBlock", DecodeObjectParticleSystem);
110 AddCallback("ParticleSys", DecodeObjectParticleSystem);
111 AddCallback("ObjectUpdate.ObjectData.ExtraParams", DecodeObjectExtraParams);
112  
113 AddCallback("ImprovedTerseObjectUpdate.ObjectData.Data", DecodeTerseUpdate);
114 AddCallback("ImprovedTerseObjectUpdate.ObjectData.TextureEntry", DecodeTerseTextureEntry);
115  
116 AddCallback("ObjectUpdateCompressed.ObjectData.Data", DecodeObjectCompressedData);
117  
118 // ImprovedTerseObjectUpdate & ObjectUpdate AttachmentPoint & ObjectUpdateCompressed
119 AddCallback("ObjectData.State", DecodeObjectState);
120 //AddCallback("ObjectUpdateCompressed.ObjectData.State", DecodeObjectState);
121 //AddCallback("ImprovedTerseObjectUpdate.ObjectData.State", DecodeObjectState);
122  
123  
124 // ChatFromSimulator
125 AddCallback("ChatData.SourceType", DecodeChatSourceType);
126 AddCallback("ChatData.ChatType", DecodeChatChatType);
127 AddCallback("ChatData.Audible", DecodeChatAudible);
128 AddCallback("AttachedSound.DataBlock.Flags", DecodeAttachedSoundFlags);
129  
130 AddCallback("RequestImage.Type", DecodeImageType);
131  
132 AddCallback("EstateOwnerMessage.ParamList.Parameter", DecodeEstateParameter);
133  
134 AddCallback("Codec", DecodeImageCodec);
135 AddCallback("Info.TeleportFlags", DecodeTeleportFlags);
136  
137 // map
138 AddCallback("MapBlockRequest.AgentData.Flags", DecodeMapRequestFlags);
139 AddCallback("MapItemRequest.AgentData.Flags", DecodeMapRequestFlags);
140 AddCallback("MapBlockReply.Data.Access", DecodeMapAccess);
141 AddCallback("FolderData.Type", DecodeFolderType);
142 AddCallback("RequestData.ItemType", DecodeGridItemType);
143  
144 // TransferRequest/TransferInfo
145 AddCallback("TransferInfo.Params", DecodeTransferParams);
146 AddCallback("TransferInfo.ChannelType", DecodeTransferChannelType);
147 AddCallback("TransferInfo.SourceType", DecodeTransferSourceType);
148 AddCallback("TransferInfo.TargetType", DecodeTransferTargetType);
149 AddCallback("TransferData.ChannelType", DecodeTransferChannelType);
150 // SendXferPacket
151 AddCallback("DataPacket.Data", DecodeBinaryToHexString);
152 // Directory Manager
153 AddCallback("DirClassifiedQuery.QueryData.QueryFlags", DecodeDirClassifiedQueryFlags);
154 AddCallback("QueryData.QueryFlags", DecodeDirQueryFlags);
155 AddCallback("Category", DecodeCategory);
156 AddCallback("QueryData.SearchType", SearchTypeFlags);
157  
158 AddCallback("ClassifiedFlags", DecodeDirClassifiedFlags);
159 AddCallback("EventFlags", DecodeEventFlags);
160  
161 AddCallback("ParcelAccessListRequest.Data.Flags", DecodeParcelACL);
162 AddCallback("ParcelAccessListReply.Data.Flags", DecodeParcelACL);
163 //AddCallback("ParcelAccessListReply.List.Flags", DecodeParcelACLReply);
164  
165 // AgentAnimation
166 AddCallback("AnimID", DecodeAnimToConst);
167  
168 AddCallback("LayerData.LayerID.Type", DecodeLayerDataType);
169  
170 AddCallback("GroupPowers", DecodeGroupPowers);
171 }
172  
173 /// <summary>
174 /// Add a custom decoder callback
175 /// </summary>
176 /// <param name="key">The key of the field to decode</param>
177 /// <param name="customPacketHandler">The custom decode handler</param>
178 public static void AddCallback(string key, CustomPacketDecoder customPacketHandler)
179 {
180 if (Callbacks.ContainsKey(key))
181 {
182 lock (Callbacks)
183 Callbacks[key].Add(customPacketHandler);
184 }
185 else
186 {
187 lock (Callbacks)
188 Callbacks.Add(key, new List<CustomPacketDecoder>() { customPacketHandler });
189 }
190 }
191  
192 /// <summary>
193 /// Remove a custom decoder callback
194 /// </summary>
195 /// <param name="key">The key of the field to decode</param>
196 /// <param name="customPacketHandler">The custom decode handler</param>
197 public static void RemoveCustomHandler(string key, CustomPacketDecoder customPacketHandler)
198 {
199 if (Callbacks.ContainsKey(key))
200 lock (Callbacks)
201 {
202 if (Callbacks[key].Contains(customPacketHandler))
203 Callbacks[key].Remove(customPacketHandler);
204 }
205 }
206  
207 #region Custom Decoders
208  
209 private static string DecodeTerseUpdate(string fieldName, object fieldData)
210 {
211 byte[] block = (byte[])fieldData;
212 int i = 4;
213  
214 StringBuilder result = new StringBuilder();
215  
216 // LocalID
217 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
218 "LocalID",
219 Utils.BytesToUInt(block, 0),
220 "Uint32");
221  
222  
223  
224 // State
225 byte point = block[i++];
226 result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
227 "State",
228 point,
229 "(" + (AttachmentPoint)point + ")",
230 "AttachmentPoint");
231  
232 // Avatar boolean
233 bool isAvatar = (block[i++] != 0);
234 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
235 "IsAvatar",
236 isAvatar,
237 "Boolean");
238  
239 // Collision normal for avatar
240 if (isAvatar)
241 {
242 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
243 "CollisionPlane",
244 new Vector4(block, i),
245 "Vector4");
246  
247 i += 16;
248 }
249  
250 // Position
251 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
252 "Position",
253 new Vector3(block, i),
254 "Vector3");
255 i += 12;
256  
257 // Velocity
258 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
259 "Velocity",
260 new Vector3(
261 Utils.UInt16ToFloat(block, i, -128.0f, 128.0f),
262 Utils.UInt16ToFloat(block, i + 2, -128.0f, 128.0f),
263 Utils.UInt16ToFloat(block, i + 4, -128.0f, 128.0f)),
264 "Vector3");
265 i += 6;
266  
267 // Acceleration
268 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
269 "Acceleration",
270 new Vector3(
271 Utils.UInt16ToFloat(block, i, -64.0f, 64.0f),
272 Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f),
273 Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)),
274 "Vector3");
275  
276 i += 6;
277 // Rotation (theta)
278 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
279 "Rotation",
280 new Quaternion(
281 Utils.UInt16ToFloat(block, i, -1.0f, 1.0f),
282 Utils.UInt16ToFloat(block, i + 2, -1.0f, 1.0f),
283 Utils.UInt16ToFloat(block, i + 4, -1.0f, 1.0f),
284 Utils.UInt16ToFloat(block, i + 6, -1.0f, 1.0f)),
285 "Quaternion");
286 i += 8;
287 // Angular velocity (omega)
288 result.AppendFormat("{0,30}: {1,-40} [{2}]",
289 "AngularVelocity",
290 new Vector3(
291 Utils.UInt16ToFloat(block, i, -64.0f, 64.0f),
292 Utils.UInt16ToFloat(block, i + 2, -64.0f, 64.0f),
293 Utils.UInt16ToFloat(block, i + 4, -64.0f, 64.0f)),
294 "Vector3");
295 //pos += 6;
296 // TODO: What is in these 6 bytes?
297 return result.ToString();
298 }
299  
300 private static string DecodeObjectCompressedData(string fieldName, object fieldData)
301 {
302 StringBuilder result = new StringBuilder();
303 byte[] block = (byte[])fieldData;
304 int i = 0;
305  
306 // UUID
307 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
308 "ID",
309 new UUID(block, 0),
310 "UUID");
311 i += 16;
312  
313 // Local ID
314 uint LocalID = (uint)(block[i++] + (block[i++] << 8) +
315 (block[i++] << 16) + (block[i++] << 24));
316  
317 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
318 "LocalID",
319 LocalID,
320 "Uint32");
321 // PCode
322 PCode pcode = (PCode)block[i++];
323  
324 result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
325 "PCode",
326 (int)pcode,
327 "(" + pcode + ")",
328 "PCode");
329  
330 // State
331 AttachmentPoint point = (AttachmentPoint)block[i++];
332 result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
333 "State",
334 (byte)point,
335 "(" + point + ")",
336 "AttachmentPoint");
337  
338 // TODO: CRC
339  
340 i += 4;
341 // Material
342 result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
343 "Material",
344 block[i],
345 "(" + (Material)block[i++] + ")",
346 "Material");
347  
348 // Click action
349 result.AppendFormat("{0,30}: {1,-3} {2,-36} [{3}]" + Environment.NewLine,
350 "ClickAction",
351 block[i],
352 "(" + (ClickAction)block[i++] + ")",
353 "ClickAction");
354  
355 // Scale
356 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
357 "Scale",
358 new Vector3(block, i),
359 "Vector3");
360 i += 12;
361  
362 // Position
363 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
364 "Position",
365 new Vector3(block, i),
366 "Vector3");
367 i += 12;
368  
369 // Rotation
370 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
371 "Rotation",
372 new Vector3(block, i),
373 "Vector3");
374  
375 i += 12;
376 // Compressed flags
377 CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block, i);
378 result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine,
379 "CompressedFlags",
380 Utils.BytesToUInt(block, i),
381 "(" + (CompressedFlags)Utils.BytesToUInt(block, i) + ")",
382 "UInt");
383 i += 4;
384  
385 // Owners ID
386 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
387 "OwnerID",
388 new UUID(block, i),
389 "UUID");
390 i += 16;
391  
392 // Angular velocity
393 if ((flags & CompressedFlags.HasAngularVelocity) != 0)
394 {
395 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
396 "AngularVelocity",
397 new Vector3(block, i),
398 "Vector3");
399 i += 12;
400 }
401  
402 // Parent ID
403 if ((flags & CompressedFlags.HasParent) != 0)
404 {
405 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
406 "ParentID",
407 (uint)(block[i++] + (block[i++] << 8) +
408 (block[i++] << 16) + (block[i++] << 24)),
409 "UInt");
410 }
411  
412 // Tree data
413 if ((flags & CompressedFlags.Tree) != 0)
414 {
415 result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine,
416 "TreeSpecies",
417 block[i++],
418 "(" + (Tree)block[i] + ")",
419 "Tree");
420 }
421  
422 // Scratch pad
423 else if ((flags & CompressedFlags.ScratchPad) != 0)
424 {
425 int size = block[i++];
426 byte[] scratch = new byte[size];
427 Buffer.BlockCopy(block, i, scratch, 0, size);
428 result.AppendFormat("{0,30}: {1,-40} [ScratchPad[]]" + Environment.NewLine,
429 "ScratchPad",
430 Utils.BytesToHexString(scratch, String.Format("{0,30}", "Data")));
431 i += size;
432 }
433  
434 // Floating text
435 if ((flags & CompressedFlags.HasText) != 0)
436 {
437 string text = String.Empty;
438 while (block[i] != 0)
439 {
440 text += (char)block[i];
441 i++;
442 }
443 i++;
444  
445 // Floating text
446 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
447 "Text",
448 text,
449 "string");
450  
451 // Text color
452 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
453 "TextColor",
454 new Color4(block, i, false),
455 "Color4");
456 i += 4;
457 }
458  
459 // Media URL
460 if ((flags & CompressedFlags.MediaURL) != 0)
461 {
462 string text = String.Empty;
463 while (block[i] != 0)
464 {
465 text += (char)block[i];
466 i++;
467 }
468 i++;
469  
470 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
471 "MediaURL",
472 text,
473 "string");
474 }
475  
476 // Particle system
477 if ((flags & CompressedFlags.HasParticles) != 0)
478 {
479 Primitive.ParticleSystem p = new Primitive.ParticleSystem(block, i);
480 result.AppendLine(DecodeObjectParticleSystem("ParticleSystem", p));
481 i += 86;
482 }
483  
484 // Extra parameters TODO:
485 Primitive prim = new Primitive();
486 i += prim.SetExtraParamsFromBytes(block, i);
487  
488 //Sound data
489 if ((flags & CompressedFlags.HasSound) != 0)
490 {
491 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
492 "SoundID",
493 new UUID(block, i),
494 "UUID");
495 i += 16;
496  
497 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
498 "SoundGain",
499 Utils.BytesToFloat(block, i),
500 "Float");
501 i += 4;
502  
503 result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine,
504 "SoundFlags",
505 block[i++],
506 "(" + (SoundFlags)block[i] + ")",
507 "SoundFlags");
508  
509 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
510 "SoundRadius",
511 Utils.BytesToFloat(block, i),
512 "Float");
513 i += 4;
514 }
515  
516 // Name values
517 if ((flags & CompressedFlags.HasNameValues) != 0)
518 {
519 string text = String.Empty;
520 while (block[i] != 0)
521 {
522 text += (char)block[i];
523 i++;
524 }
525 i++;
526  
527 // Parse the name values
528 if (text.Length > 0)
529 {
530 string[] lines = text.Split('\n');
531 NameValue[] nameValues = new NameValue[lines.Length];
532  
533 for (int j = 0; j < lines.Length; j++)
534 {
535 if (!String.IsNullOrEmpty(lines[j]))
536 {
537 NameValue nv = new NameValue(lines[j]);
538 nameValues[j] = nv;
539 }
540 }
541 DecodeNameValue("NameValues", nameValues);
542 }
543 }
544  
545 result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine,
546 "PathCurve",
547 block[i],
548 "(" + (PathCurve)block[i++] + ")",
549 "PathCurve");
550  
551 ushort pathBegin = Utils.BytesToUInt16(block, i);
552 i += 2;
553 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
554 "PathBegin",
555 Primitive.UnpackBeginCut(pathBegin),
556 "float");
557  
558 ushort pathEnd = Utils.BytesToUInt16(block, i);
559 i += 2;
560 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
561 "PathEnd",
562 Primitive.UnpackEndCut(pathEnd),
563 "float");
564  
565 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
566 "PathScaleX",
567 Primitive.UnpackPathScale(block[i++]),
568 "float");
569  
570 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
571 "PathScaleY",
572 Primitive.UnpackPathScale(block[i++]),
573 "float");
574  
575 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
576 "PathShearX",
577 Primitive.UnpackPathShear((sbyte)block[i++]),
578 "float");
579  
580 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
581 "PathShearY",
582 Primitive.UnpackPathShear((sbyte)block[i++]),
583 "float");
584  
585 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
586 "PathTwist",
587 Primitive.UnpackPathTwist((sbyte)block[i++]),
588 "float");
589  
590 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
591 "PathTwistBegin",
592 Primitive.UnpackPathTwist((sbyte)block[i++]),
593 "float");
594  
595 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
596 "PathRadiusOffset",
597 Primitive.UnpackPathTwist((sbyte)block[i++]),
598 "float");
599  
600 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
601 "PathTaperX",
602 Primitive.UnpackPathTaper((sbyte)block[i++]),
603 "float");
604  
605 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
606 "PathTaperY",
607 Primitive.UnpackPathTaper((sbyte)block[i++]),
608 "float");
609  
610 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
611 "PathRevolutions",
612 Primitive.UnpackPathRevolutions(block[i++]),
613 "float");
614  
615 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
616 "PathSkew",
617 Primitive.UnpackPathTwist((sbyte)block[i++]),
618 "float");
619  
620 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
621 "ProfileCurve",
622 block[i++],
623 "float");
624  
625 ushort profileBegin = Utils.BytesToUInt16(block, i);
626 i += 2;
627 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
628 "ProfileBegin",
629 Primitive.UnpackBeginCut(profileBegin),
630 "float");
631  
632 ushort profileEnd = Utils.BytesToUInt16(block, i);
633 i += 2;
634 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
635 "ProfileEnd",
636 Primitive.UnpackEndCut(profileEnd),
637 "float");
638  
639 ushort profileHollow = Utils.BytesToUInt16(block, i);
640 i += 2;
641 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
642 "ProfileHollow",
643 Primitive.UnpackProfileHollow(profileHollow),
644 "float");
645  
646 int textureEntryLength = (int)Utils.BytesToUInt(block, i);
647 i += 4;
648 //prim.Textures = new Primitive.TextureEntry(block, i, textureEntryLength);
649 String s = DecodeTextureEntry("TextureEntry", new Primitive.TextureEntry(block, i, textureEntryLength));
650 result.AppendLine(s);
651 i += textureEntryLength;
652  
653 // Texture animation
654 if ((flags & CompressedFlags.TextureAnimation) != 0)
655 {
656 i += 4;
657 string a = DecodeObjectTextureAnim("TextureAnimation", new Primitive.TextureAnimation(block, i));
658 result.AppendLine(a);
659 }
660  
661 return result.ToString();
662 }
663  
664 private static string DecodeObjectData(string fieldName, object fieldData)
665 {
666 byte[] data = (byte[])fieldData;
667 if (data.Length == 1)
668 {
669 return String.Format("{0,30}: {1,2} {2,-38} [{3}]",
670 fieldName + " (Tree Species)",
671 fieldData,
672 "(" + (Tree)(byte)fieldData + ")",
673 fieldData.GetType().Name);
674 }
675 else if (data.Length == 60)
676 {
677 /* TODO: these are likely useful packed fields,
678 * need to unpack them */
679 return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName));
680 }
681 else
682 {
683 return Utils.BytesToHexString((byte[])fieldData, String.Format("{0,30}", fieldName));
684 }
685 }
686  
687 private static string DecodeObjectTextureAnim(string fieldName, object fieldData)
688 {
689 StringBuilder result = new StringBuilder();
690 Primitive.TextureAnimation TextureAnim;
691 if (fieldData is Primitive.TextureAnimation)
692 TextureAnim = (Primitive.TextureAnimation)fieldData;
693 else
694 TextureAnim = new Primitive.TextureAnimation((byte[])fieldData, 0);
695  
696 result.AppendFormat("{0,30}", " <TextureAnimation>" + Environment.NewLine);
697 GenericTypeDecoder(TextureAnim, ref result);
698 result.AppendFormat("{0,30}", "</TextureAnimation>");
699  
700 return result.ToString();
701 }
702  
703 private static string DecodeEstateParameter(string fieldName, object fieldData)
704 {
705 byte[] bytes = (byte[])fieldData;
706  
707 if (bytes.Length == 17)
708 {
709 return String.Format("{0,30}: {1,-40} [UUID]", fieldName, new UUID((byte[])fieldData, 0));
710 }
711 else
712 {
713 return String.Format("{0,30}: {1,-40} [Byte[]]", fieldName, Utils.BytesToString((byte[])fieldData));
714 }
715 }
716  
717 private static string DecodeNameValue(string fieldName, object fieldData)
718 {
719 string nameValue = Utils.BytesToString((byte[])fieldData);
720 NameValue[] nameValues = null;
721 if (nameValue.Length > 0)
722 {
723 string[] lines = nameValue.Split('\n');
724 nameValues = new NameValue[lines.Length];
725  
726 for (int i = 0; i < lines.Length; i++)
727 {
728 if (!String.IsNullOrEmpty(lines[i]))
729 {
730 NameValue nv = new NameValue(lines[i]);
731 nameValues[i] = nv;
732 }
733 }
734 }
735  
736 StringBuilder result = new StringBuilder();
737 result.AppendFormat("{0,30}", " <NameValues>" + Environment.NewLine);
738 if (nameValues != null)
739 {
740 for (int i = 0; i < nameValues.Length; i++)
741 {
742 result.AppendFormat(
743 "{0,30}: Name={1} Value={2} Class={3} Type={4} Sendto={5}" + Environment.NewLine, "NameValue",
744 nameValues[i].Name, nameValues[i].Value, nameValues[i].Class, nameValues[i].Type, nameValues[i].Sendto);
745 }
746 }
747 result.AppendFormat("{0,30}", "</NameValues>");
748 return result.ToString();
749 }
750  
751 private static string DecodeObjectExtraParams(string fieldName, object fieldData)
752 {
753  
754 byte[] data = (byte[])fieldData;
755  
756 int i = 0;
757 //int totalLength = 1;
758  
759 Primitive.FlexibleData Flexible = null;
760 Primitive.LightData Light = null;
761 Primitive.SculptData Sculpt = null;
762  
763 byte extraParamCount = data[i++];
764  
765 for (int k = 0; k < extraParamCount; k++)
766 {
767 ExtraParamType type = (ExtraParamType)Utils.BytesToUInt16(data, i);
768 i += 2;
769  
770 uint paramLength = Utils.BytesToUInt(data, i);
771 i += 4;
772  
773 if (type == ExtraParamType.Flexible)
774 Flexible = new Primitive.FlexibleData(data, i);
775 else if (type == ExtraParamType.Light)
776 Light = new Primitive.LightData(data, i);
777 else if (type == ExtraParamType.Sculpt)
778 Sculpt = new Primitive.SculptData(data, i);
779  
780 i += (int)paramLength;
781 //totalLength += (int)paramLength + 6;
782 }
783  
784 StringBuilder result = new StringBuilder();
785 result.AppendFormat("{0,30}", "<ExtraParams>" + Environment.NewLine);
786 if (Flexible != null)
787 {
788 result.AppendFormat("{0,30}", "<Flexible>" + Environment.NewLine);
789 GenericTypeDecoder(Flexible, ref result);
790 result.AppendFormat("{0,30}", "</Flexible>" + Environment.NewLine);
791 }
792  
793 if (Sculpt != null)
794 {
795 result.AppendFormat("{0,30}", "<Sculpt>" + Environment.NewLine);
796 GenericTypeDecoder(Sculpt, ref result);
797 result.AppendFormat("{0,30}", "</Sculpt>" + Environment.NewLine);
798 }
799  
800 if (Light != null)
801 {
802 result.AppendFormat("{0,30}", "<Light>" + Environment.NewLine);
803 GenericTypeDecoder(Light, ref result);
804 result.AppendFormat("{0,30}", "</Light>" + Environment.NewLine);
805 }
806  
807 result.AppendFormat("{0,30}", "</ExtraParams>");
808 return result.ToString();
809 }
810  
811 private static string DecodeObjectParticleSystem(string fieldName, object fieldData)
812 {
813 StringBuilder result = new StringBuilder();
814 Primitive.ParticleSystem ParticleSys;
815 if (fieldData is Primitive.ParticleSystem)
816 ParticleSys = (Primitive.ParticleSystem)fieldData;
817 else
818 ParticleSys = new Primitive.ParticleSystem((byte[])fieldData, 0);
819  
820 result.AppendFormat("{0,30}", "<ParticleSystem>" + Environment.NewLine);
821 GenericTypeDecoder(ParticleSys, ref result);
822 result.AppendFormat("{0,30}", "</ParticleSystem>");
823  
824 return result.ToString();
825 }
826  
827 private static void GenericTypeDecoder(object obj, ref StringBuilder result)
828 {
829 FieldInfo[] fields = obj.GetType().GetFields();
830  
831 foreach (FieldInfo field in fields)
832 {
833 String special;
834 if (SpecialDecoder("a" + "." + "b" + "." + field.Name,
835 field.GetValue(obj), out special))
836 {
837 result.AppendLine(special);
838 }
839 else
840 {
841 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
842 field.Name,
843 field.GetValue(obj),
844 field.FieldType.Name);
845 }
846 }
847 }
848  
849 private static string DecodeObjectPCode(string fieldName, object fieldData)
850 {
851 return String.Format("{0,30}: {1,-3} {2,-36} [PCode]",
852 fieldName,
853 fieldData,
854 "(" + (PCode)(byte)fieldData + ")");
855 }
856  
857 private static string DecodeImageType(string fieldName, object fieldData)
858 {
859 return String.Format("{0,30}: {1,-3} {2,-36} [ImageType]",
860 fieldName,
861 fieldData,
862 "(" + (ImageType)(byte)fieldData + ")");
863 }
864  
865 private static string DecodeImageCodec(string fieldName, object fieldData)
866 {
867 return String.Format("{0,30}: {1,-3} {2,-36} [ImageCodec]",
868 fieldName,
869 fieldData,
870 "(" + (ImageCodec)(byte)fieldData + ")");
871 }
872  
873 private static string DecodeObjectMaterial(string fieldName, object fieldData)
874 {
875 return String.Format("{0,30}: {1,-3} {2,-36} [Material]",
876 fieldName,
877 fieldData,
878 "(" + (Material)(byte)fieldData + ")");
879 }
880  
881 private static string DecodeObjectClickAction(string fieldName, object fieldData)
882 {
883 return String.Format("{0,30}: {1,-3} {2,-36} [ClickAction]",
884 fieldName,
885 fieldData,
886 "(" + (ClickAction)(byte)fieldData + ")");
887 }
888  
889 private static string DecodeEventFlags(string fieldName, object fieldData)
890 {
891 return String.Format("{0,30}: {1,-3} {2,-36} [EventFlags]",
892 fieldName,
893 fieldData,
894 "(" + (DirectoryManager.EventFlags)(uint)fieldData + ")");
895 }
896  
897 private static string DecodeDirQueryFlags(string fieldName, object fieldData)
898 {
899 return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.DirFindFlags]",
900 fieldName,
901 fieldData,
902 "(" + (DirectoryManager.DirFindFlags)(uint)fieldData + ")");
903 }
904  
905 private static string DecodeDirClassifiedQueryFlags(string fieldName, object fieldData)
906 {
907 return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedQueryFlags]",
908 fieldName,
909 fieldData,
910 "(" + (DirectoryManager.ClassifiedQueryFlags)(uint)fieldData + ")");
911 }
912  
913 private static string DecodeDirClassifiedFlags(string fieldName, object fieldData)
914 {
915 return String.Format("{0,30}: {1,-10} {2,-29} [ClassifiedFlags]",
916 fieldName,
917 fieldData,
918 "(" + (DirectoryManager.ClassifiedFlags)(byte)fieldData + ")");
919 }
920  
921 private static string DecodeGroupPowers(string fieldName, object fieldData)
922 {
923 return String.Format("{0,30}: {1,-20} {2,-19} [GroupPowers]",
924 fieldName,
925 fieldData,
926 "(" + (GroupPowers)(ulong)fieldData + ")");
927 }
928  
929 private static string DecodeParcelACL(string fieldName, object fieldData)
930 {
931 return String.Format("{0,30}: {1,-10} {2,-29} [AccessList]",
932 fieldName,
933 fieldData,
934 "(" + (AccessList)(uint)fieldData + ")");
935 }
936  
937 private static string SearchTypeFlags(string fieldName, object fieldData)
938 {
939 return String.Format("{0,30}: {1,-10} {2,-29} [DirectoryManager.SearchTypeFlags]",
940 fieldName,
941 fieldData,
942 "(" + (DirectoryManager.SearchTypeFlags)(uint)fieldData + ")");
943 }
944  
945 private static string DecodeCategory(string fieldName, object fieldData)
946 {
947 return String.Format("{0,30}: {1,-3} {2,-36} [ParcelCategory]",
948 fieldName,
949 fieldData,
950 "(" + fieldData + ")");
951 }
952  
953 private static string DecodeObjectUpdateFlags(string fieldName, object fieldData)
954 {
955 return String.Format("{0,30}: {1,-10} {2,-29} [PrimFlags]",
956 fieldName,
957 fieldData,
958 "(" + (PrimFlags)(uint)fieldData + ")");
959 }
960  
961 private static string DecodeTeleportFlags(string fieldName, object fieldData)
962 {
963 return String.Format("{0,30}: {1,-10} {2,-29} [TeleportFlags]",
964 fieldName,
965 fieldData,
966 "(" + (TeleportFlags)(uint)fieldData + ")");
967 }
968  
969 private static string DecodeScriptControls(string fieldName, object fieldData)
970 {
971 return String.Format("{0,30}: {1,-10} {2,-29} [AgentManager.ControlFlags]",
972 fieldName,
973 (uint)fieldData,
974 "(" + (AgentManager.ControlFlags)(uint)fieldData + ")");
975 }
976  
977 private static string DecodeColorField(string fieldName, object fieldData)
978 {
979 return String.Format("{0,30}: {1,-40} [Color4]",
980 fieldName,
981 fieldData.GetType().Name.Equals("Color4") ? (Color4)fieldData : new Color4((byte[])fieldData, 0, false));
982 }
983  
984 private static string DecodeTimeStamp(string fieldName, object fieldData)
985 {
986 if (fieldData is Int32 && (int)fieldData > 0)
987 return String.Format("{0,30}: {1,-10} {2,-29} [{3}]",
988 fieldName,
989 fieldData,
990 "(" + Utils.UnixTimeToDateTime((int)fieldData) + ")",
991 fieldData.GetType().Name);
992 else if (fieldData is uint && (uint)fieldData > 0)
993 return String.Format("{0,30}: {1,-10} {2,-29} [{3}]",
994 fieldName,
995 fieldData,
996 "(" + Utils.UnixTimeToDateTime((uint)fieldData) + ")",
997 fieldData.GetType().Name);
998 else
999 return String.Format("{0,30}: {1,-40} [{2}]",
1000 fieldName,
1001 fieldData,
1002 fieldData.GetType().Name);
1003 }
1004  
1005 private static string DecodeBinaryBucket(string fieldName, object fieldData)
1006 {
1007 byte[] bytes = (byte[])fieldData;
1008 string bucket = String.Empty;
1009 if (bytes.Length == 1)
1010 {
1011 bucket = String.Format("{0}", bytes[0]);
1012 }
1013 else if (bytes.Length == 17)
1014 {
1015 bucket = String.Format("{0,-36} {1} ({2})",
1016 new UUID(bytes, 1),
1017 bytes[0],
1018 (AssetType)(sbyte)bytes[0]);
1019 }
1020 else if (bytes.Length == 16) // the folder ID for the asset to be stored into if we accept an inventory offer
1021 {
1022 bucket = new UUID(bytes, 0).ToString();
1023 }
1024 else
1025 {
1026 bucket = Utils.BytesToString(bytes); // we'll try a string lastly
1027 }
1028  
1029 return String.Format("{0,30}: {1,-40} [Byte[{2}]]", fieldName, bucket, bytes.Length);
1030 }
1031  
1032 private static string DecodeBinaryToHexString(string fieldName, object fieldData)
1033 {
1034 return String.Format("{0,30}",
1035 Utils.BytesToHexString((byte[])fieldData,
1036 String.Format("{0,30}", fieldName)));
1037 }
1038  
1039 private static string DecodeWearableType(string fieldName, object fieldData)
1040 {
1041 return String.Format("{0,30}: {1,-2} {2,-37} [WearableType]",
1042 fieldName,
1043 (byte)fieldData,
1044 "(" + (WearableType)fieldData + ")");
1045 }
1046  
1047 private static string DecodeInventoryType(string fieldName, object fieldData)
1048 {
1049 return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]",
1050 fieldName,
1051 (sbyte)fieldData,
1052 "(" + (AssetType)(sbyte)fieldData + ")");
1053 }
1054  
1055 private static string DecodeInventorySort(string fieldName, object fieldData)
1056 {
1057 return String.Format("{0,30}: {1,-2} {2,-37} [InventorySortOrder]",
1058 fieldName,
1059 fieldData,
1060 "(" + (InventorySortOrder)(int)fieldData + ")");
1061 }
1062  
1063 private static string DecodeInventoryInvType(string fieldName, object fieldData)
1064 {
1065 return String.Format("{0,30}: {1,-2} {2,-37} [InventoryType]",
1066 fieldName,
1067 (sbyte)fieldData,
1068 "(" + (InventoryType)fieldData + ")");
1069 }
1070  
1071 private static string DecodeFolderType(string fieldName, object fieldData)
1072 {
1073 return String.Format("{0,30}: {1,-2} {2,-37} [AssetType]",
1074 fieldName,
1075 (sbyte)fieldData,
1076 "(" + (AssetType)fieldData + ")");
1077 }
1078  
1079 private static string DecodeInventoryFlags(string fieldName, object fieldData)
1080 {
1081 return String.Format("{0,30}: {1,-2} {2,-37} [InventoryItemFlags]",
1082 fieldName,
1083 (uint)fieldData,
1084 "(" + (InventoryItemFlags)(uint)fieldData + ")");
1085 }
1086  
1087 private static string DecodeObjectSaleType(string fieldName, object fieldData)
1088 {
1089 return String.Format("{0,30}: {1,-2} {2,-37} [SaleType]",
1090 fieldName,
1091 (byte)fieldData,
1092 "(" + (SaleType)fieldData + ")");
1093 }
1094  
1095 private static string DecodeRegionFlags(string fieldName, object fieldData)
1096 {
1097 return String.Format("{0,30}: {1,-2} {2,-37} [RegionFlags]",
1098 fieldName,
1099 fieldData,
1100 "(" + (RegionFlags)(uint)fieldData + ")");
1101 }
1102  
1103 private static string DecodeTransferParams(string fieldName, object fieldData)
1104 {
1105 byte[] paramData = (byte[])fieldData;
1106 StringBuilder result = new StringBuilder();
1107 result.AppendLine(" <Params>");
1108 if (paramData.Length == 20)
1109 {
1110 result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
1111 "AssetID",
1112 new UUID(paramData, 0));
1113  
1114 result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine,
1115 "AssetType",
1116 (sbyte)paramData[16],
1117 "(" + (AssetType)(sbyte)paramData[16] + ")");
1118  
1119 }
1120 else if (paramData.Length == 100)
1121 {
1122 //UUID agentID = new UUID(info.TransferInfo.Params, 0);
1123 result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
1124 "AgentID",
1125 new UUID(paramData, 0));
1126  
1127 //UUID sessionID = new UUID(info.TransferInfo.Params, 16);
1128 result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
1129 "SessionID",
1130 new UUID(paramData, 16));
1131 //UUID ownerID = new UUID(info.TransferInfo.Params, 32);
1132 result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
1133 "OwnerID",
1134 new UUID(paramData, 32));
1135 //UUID taskID = new UUID(info.TransferInfo.Params, 48);
1136 result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
1137 "TaskID",
1138 new UUID(paramData, 48));
1139 //UUID itemID = new UUID(info.TransferInfo.Params, 64);
1140 result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
1141 "ItemID",
1142 new UUID(paramData, 64));
1143  
1144 result.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine,
1145 "AssetID",
1146 new UUID(paramData, 80));
1147  
1148 result.AppendFormat("{0,30}: {1,-2} {2,-37} [AssetType]" + Environment.NewLine,
1149 "AssetType",
1150 (sbyte)paramData[96],
1151 "(" + (AssetType)(sbyte)paramData[96] + ")");
1152 }
1153 else
1154 {
1155 Console.WriteLine("Oh Poop!");
1156 }
1157  
1158 result.Append("</Params>");
1159  
1160 return result.ToString();
1161 }
1162  
1163 private static string DecodeTransferChannelType(string fieldName, object fieldData)
1164 {
1165 return String.Format("{0,30}: {1,-2} {2,-37} [ChannelType]",
1166 fieldName,
1167 fieldData,
1168 "(" + (ChannelType)(int)fieldData + ")");
1169 }
1170  
1171 private static string DecodeTransferSourceType(string fieldName, object fieldData)
1172 {
1173 return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]",
1174 fieldName,
1175 fieldData,
1176 "(" + (SourceType)(int)fieldData + ")");
1177 }
1178  
1179 private static string DecodeTransferTargetType(string fieldName, object fieldData)
1180 {
1181 return String.Format("{0,30}: {1,-2} {2,-37} [TargetType]",
1182 fieldName,
1183 fieldData,
1184 "(" + (TargetType)(int)fieldData + ")");
1185 }
1186  
1187 private static string DecodeMapRequestFlags(string fieldName, object fieldData)
1188 {
1189 return String.Format("{0,30}: {1,-2} {2,-37} [GridLayerType]",
1190 fieldName,
1191 fieldData,
1192 "(" + (GridLayerType)(uint)fieldData + ")");
1193 }
1194  
1195 private static string DecodeGridItemType(string fieldName, object fieldData)
1196 {
1197 return String.Format("{0,30}: {1,-2} {2,-37} [GridItemType]",
1198 fieldName,
1199 fieldData,
1200 "(" + (GridItemType)(uint)fieldData + ")");
1201  
1202 }
1203  
1204 private static string DecodeLayerDataType(string fieldName, object fieldData)
1205 {
1206 return String.Format("{0,30}: {1,-2} {2,-37} [LayerType]",
1207 fieldName,
1208 fieldData,
1209 "(" + (TerrainPatch.LayerType)(byte)fieldData + ")");
1210 }
1211  
1212 private static string DecodeMapAccess(string fieldName, object fieldData)
1213 {
1214 return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]",
1215 fieldName,
1216 fieldData,
1217 "(" + (SimAccess)(byte)fieldData + ")");
1218 }
1219  
1220 private static string DecodeSimAccess(string fieldName, object fieldData)
1221 {
1222 return String.Format("{0,30}: {1,-2} {2,-37} [SimAccess]",
1223 fieldName,
1224 (byte)fieldData,
1225 "(" + (SimAccess)fieldData + ")");
1226 }
1227  
1228 private static string DecodeAttachedSoundFlags(string fieldName, object fieldData)
1229 {
1230 return String.Format("{0,30}: {1,-2} {2,-37} [SoundFlags]",
1231 fieldName,
1232 (byte)fieldData,
1233 "(" + (SoundFlags)fieldData + ")");
1234 }
1235  
1236  
1237 private static string DecodeChatSourceType(string fieldName, object fieldData)
1238 {
1239 return String.Format("{0,30}: {1,-2} {2,-37} [SourceType]",
1240 fieldName,
1241 fieldData,
1242 "(" + (SourceType)(byte)fieldData + ")");
1243 }
1244  
1245 private static string DecodeChatChatType(string fieldName, object fieldData)
1246 {
1247 return String.Format("{0,30}: {1,-2} {2,-37} [ChatType]",
1248 fieldName,
1249 (byte)fieldData,
1250 "(" + (ChatType)fieldData + ")");
1251 }
1252  
1253 private static string DecodeChatAudible(string fieldName, object fieldData)
1254 {
1255 return String.Format("{0,30}: {1,-2} {2,-37} [ChatAudibleLevel]",
1256 fieldName,
1257 (byte)fieldData,
1258 "(" + (ChatAudibleLevel)(byte)fieldData + ")");
1259 }
1260  
1261 private static string DecodeImageData(string fieldName, object fieldData)
1262 {
1263 return String.Format("{0,10}",
1264 Utils.BytesToHexString((byte[])fieldData,
1265 String.Format("{0,30}", fieldName)));
1266 }
1267  
1268 private static string DecodeTerseTextureEntry(string fieldName, object fieldData)
1269 {
1270 byte[] block = (byte[])fieldData;
1271  
1272 Primitive.TextureEntry te = new Primitive.TextureEntry(block, 4, block.Length - 4);
1273  
1274 StringBuilder result = new StringBuilder();
1275  
1276 result.AppendFormat("{0,30}", " <TextureEntry>" + Environment.NewLine);
1277 if (te.DefaultTexture != null)
1278 {
1279 result.AppendFormat("{0,30}", " <DefaultTexture>" + Environment.NewLine);
1280 GenericFieldsDecoder(te.DefaultTexture, ref result);
1281 GenericPropertiesDecoder(te.DefaultTexture, ref result);
1282 result.AppendFormat("{0,30}", " </DefaultTexture>" + Environment.NewLine);
1283 }
1284 result.AppendFormat("{0,30}", " <FaceTextures>" + Environment.NewLine);
1285 for (int i = 0; i < te.FaceTextures.Length; i++)
1286 {
1287 if (te.FaceTextures[i] != null)
1288 {
1289 result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i);
1290 GenericFieldsDecoder(te.FaceTextures[i], ref result);
1291 GenericPropertiesDecoder(te.FaceTextures[i], ref result);
1292 }
1293 }
1294 result.AppendFormat("{0,30}", " </FaceTextures>" + Environment.NewLine);
1295 result.AppendFormat("{0,30}", "</TextureEntry>");
1296  
1297 return result.ToString();
1298 }
1299  
1300 private static string DecodeTextureEntry(string fieldName, object fieldData)
1301 {
1302 Primitive.TextureEntry te;
1303 if (fieldData is Primitive.TextureEntry)
1304 te = (Primitive.TextureEntry)fieldData;
1305 else
1306 {
1307 byte[] tebytes = (byte[])fieldData;
1308 te = new Primitive.TextureEntry(tebytes, 0, tebytes.Length);
1309 }
1310  
1311 StringBuilder result = new StringBuilder();
1312  
1313 result.AppendFormat("{0,30}", " <TextureEntry>" + Environment.NewLine);
1314 if (te.DefaultTexture != null)
1315 {
1316 result.AppendFormat("{0,30}", " <DefaultTexture>" + Environment.NewLine);
1317 GenericFieldsDecoder(te.DefaultTexture, ref result);
1318 GenericPropertiesDecoder(te.DefaultTexture, ref result);
1319 result.AppendFormat("{0,30}", " </DefaultTexture>" + Environment.NewLine);
1320 }
1321 result.AppendFormat("{0,30}", " <FaceTextures>" + Environment.NewLine);
1322 for (int i = 0; i < te.FaceTextures.Length; i++)
1323 {
1324 if (te.FaceTextures[i] != null)
1325 {
1326 result.AppendFormat("{0,30}[{1}]" + Environment.NewLine, "FaceTexture", i);
1327 GenericFieldsDecoder(te.FaceTextures[i], ref result);
1328 GenericPropertiesDecoder(te.FaceTextures[i], ref result);
1329 }
1330 }
1331 result.AppendFormat("{0,30}", " </FaceTextures>" + Environment.NewLine);
1332 result.AppendFormat("{0,30}", "</TextureEntry>");
1333  
1334 return result.ToString();
1335 }
1336  
1337 private static void GenericFieldsDecoder(object obj, ref StringBuilder result)
1338 {
1339 Type parcelType = obj.GetType();
1340 FieldInfo[] fields = parcelType.GetFields();
1341 foreach (FieldInfo field in fields)
1342 {
1343 String special;
1344 if (SpecialDecoder("a" + "." + "b" + "." + field.Name,
1345 field.GetValue(obj), out special))
1346 {
1347 result.AppendLine(special);
1348 }
1349 else
1350 {
1351 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
1352 field.Name,
1353 field.GetValue(obj),
1354 field.FieldType.Name);
1355 }
1356 }
1357 }
1358  
1359 private static void GenericPropertiesDecoder(object obj, ref StringBuilder result)
1360 {
1361 Type parcelType = obj.GetType();
1362 PropertyInfo[] propertyInfos = parcelType.GetProperties();
1363 foreach (PropertyInfo property in propertyInfos)
1364 {
1365 String special;
1366 if (SpecialDecoder("a" + "." + "b" + "." + property.Name,
1367 property.GetValue(obj, null), out special))
1368 {
1369 result.AppendLine(special);
1370 }
1371 else
1372 {
1373 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
1374 property.Name,
1375 property.GetValue(obj, null),
1376 property.PropertyType.Name);
1377 }
1378 }
1379 }
1380  
1381 private static string DecodeDialog(string fieldName, object fieldData)
1382 {
1383 return String.Format("{0,30}: {1,-2} {2,-37} [{3}]",
1384 fieldName,
1385 (byte)fieldData,
1386 "(" + (InstantMessageDialog)fieldData + ")",
1387 fieldData.GetType().Name);
1388 }
1389  
1390 private static string DecodeControlFlags(string fieldName, object fieldData)
1391 {
1392 return String.Format("{0,30}: {1,-10} {2,-29} [{3}]",
1393 fieldName,
1394 fieldData,
1395 "(" + (AgentManager.ControlFlags)(uint)fieldData + ")",
1396 fieldData.GetType().Name);
1397 }
1398  
1399 private static string DecodePermissionMask(string fieldName, object fieldData)
1400 {
1401 return String.Format("{0,30}: {1,-10} {2,-29} [{3}]",
1402 fieldName,
1403 (uint)fieldData,
1404 "(" + (PermissionMask)fieldData + ")",
1405 fieldData.GetType().Name);
1406 }
1407  
1408 private static string DecodeViewerEffectTypeData(string fieldName, object fieldData)
1409 {
1410 byte[] data = (byte[])fieldData;
1411 StringBuilder sb = new StringBuilder();
1412 if (data.Length == 56 || data.Length == 57)
1413 {
1414 UUID sourceAvatar = new UUID(data, 0);
1415 UUID targetObject = new UUID(data, 16);
1416 Vector3d targetPos = new Vector3d(data, 32);
1417 sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Source AvatarID=" + sourceAvatar);
1418 sb.AppendFormat("{0,30}: {1,-40} [UUID]" + Environment.NewLine, fieldName, "Target ObjectID=" + targetObject);
1419  
1420  
1421 float lx, ly;
1422 Helpers.GlobalPosToRegionHandle((float)targetPos.X, (float)targetPos.Y, out lx, out ly);
1423  
1424 sb.AppendFormat("{0,30}: {1,-40} [Vector3d]", fieldName, targetPos);
1425  
1426 if (data.Length == 57)
1427 {
1428 sb.AppendLine();
1429 sb.AppendFormat("{0,30}: {1,-17} {2,-22} [Byte]", fieldName, "Point At Type=" + data[56],
1430 "(" + (PointAtType)data[56] + ")");
1431 }
1432  
1433 return sb.ToString();
1434 }
1435 else
1436 {
1437 return String.Format("{0,30}: (No Decoder) Length={1}" + Environment.NewLine, fieldName, data.Length) + Utils.BytesToHexString(data, String.Format("{0,30}", ""));
1438 }
1439 }
1440  
1441 private static string DecodeAgentState(string fieldName, object fieldData)
1442 {
1443 return String.Format("{0,30}: {1,-2} {2,-37} [AgentState]",
1444 fieldName,
1445 fieldData,
1446 "(" + (AgentState)(byte)fieldData + ")");
1447 }
1448  
1449 private static string DecodeAgentFlags(string fieldName, object fieldData)
1450 {
1451 return String.Format("{0,30}: {1,-2} {2,-37} [AgentFlags]",
1452 fieldName,
1453 fieldData,
1454 "(" + (AgentFlags)(byte)fieldData + ")");
1455 }
1456  
1457 private static string DecodeObjectState(string fieldName, object fieldData)
1458 {
1459 return String.Format("{0,30}: {1,-2} {2,-37} [AttachmentPoint]",
1460 fieldName,
1461 fieldData,
1462 "(" + (AttachmentPoint)(byte)fieldData + ")");
1463 }
1464  
1465 private static string DecodeViewerEffectType(string fieldName, object fieldData)
1466 {
1467 return String.Format("{0,30}: {1,-2} {2,-37} [{3}]",
1468 fieldName,
1469 fieldData,
1470 "(" + (EffectType)(byte)fieldData + ")",
1471 fieldData.GetType().Name);
1472 }
1473  
1474 private static string DecodeAnimToConst(string fieldName, object fieldData)
1475 {
1476 string animConst = "UUID";
1477 Dictionary<UUID, string> animsDict = Animations.ToDictionary();
1478 if (animsDict.ContainsKey((UUID)fieldData))
1479 animConst = animsDict[(UUID)fieldData];
1480 return String.Format("{0,30}: {1,-40} [{2}]",
1481 fieldName,
1482 fieldData,
1483 animConst);
1484 }
1485 #endregion
1486  
1487 /// <summary>
1488 /// Creates a formatted string containing the values of a Packet
1489 /// </summary>
1490 /// <param name="packet">The Packet</param>
1491 /// <returns>A formatted string of values of the nested items in the Packet object</returns>
1492 public static string PacketToString(Packet packet)
1493 {
1494 StringBuilder result = new StringBuilder();
1495  
1496 result.AppendFormat("Packet Type: {0} http://lib.openmetaverse.org/wiki/{0} http://wiki.secondlife.com/wiki/{0}" + Environment.NewLine, packet.Type);
1497 result.AppendLine("[Packet Header]");
1498 // payload
1499 result.AppendFormat("Sequence: {0}" + Environment.NewLine, packet.Header.Sequence);
1500 result.AppendFormat(" Options: {0}" + Environment.NewLine, InterpretOptions(packet.Header));
1501 result.AppendLine();
1502  
1503 result.AppendLine("[Packet Payload]");
1504  
1505 FieldInfo[] fields = packet.GetType().GetFields();
1506  
1507 for (int i = 0; i < fields.Length; i++)
1508 {
1509 // we're not interested in any of these here
1510 if (fields[i].Name == "Type" || fields[i].Name == "Header" || fields[i].Name == "HasVariableBlocks")
1511 continue;
1512  
1513 if (fields[i].FieldType.IsArray)
1514 {
1515 result.AppendFormat("{0,30} []" + Environment.NewLine, "-- " + fields[i].Name + " --");
1516 RecursePacketArray(fields[i], packet, ref result);
1517 }
1518 else
1519 {
1520 result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + fields[i].Name + " --");
1521 RecursePacketField(fields[i], packet, ref result);
1522 }
1523 }
1524 return result.ToString();
1525 }
1526  
1527 public static string InterpretOptions(Header header)
1528 {
1529 return "["
1530 + (header.AppendedAcks ? "Ack" : " ")
1531 + " "
1532 + (header.Resent ? "Res" : " ")
1533 + " "
1534 + (header.Reliable ? "Rel" : " ")
1535 + " "
1536 + (header.Zerocoded ? "Zer" : " ")
1537 + "]"
1538 ;
1539 }
1540  
1541 private static void RecursePacketArray(FieldInfo fieldInfo, object packet, ref StringBuilder result)
1542 {
1543 var packetDataObject = fieldInfo.GetValue(packet);
1544  
1545 foreach (object nestedArrayRecord in packetDataObject as Array)
1546 {
1547 FieldInfo[] fields = nestedArrayRecord.GetType().GetFields();
1548  
1549 for (int i = 0; i < fields.Length; i++)
1550 {
1551 String special;
1552 if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + fields[i].Name,
1553 fields[i].GetValue(nestedArrayRecord), out special))
1554 {
1555 result.AppendLine(special);
1556 }
1557 else if (fields[i].FieldType.IsArray) // default for an array (probably a byte[])
1558 {
1559 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
1560 fields[i].Name,
1561 Utils.BytesToString((byte[])fields[i].GetValue(nestedArrayRecord)),
1562 /*fields[i].GetValue(nestedArrayRecord).GetType().Name*/ "String");
1563 }
1564 else // default for a field
1565 {
1566 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
1567 fields[i].Name,
1568 fields[i].GetValue(nestedArrayRecord),
1569 fields[i].GetValue(nestedArrayRecord).GetType().Name);
1570 }
1571 }
1572  
1573 // Handle Properties
1574 foreach (PropertyInfo propertyInfo in nestedArrayRecord.GetType().GetProperties())
1575 {
1576 if (propertyInfo.Name.Equals("Length"))
1577 continue;
1578  
1579 string special;
1580 if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name,
1581 propertyInfo.GetValue(nestedArrayRecord, null),
1582 out special))
1583 {
1584 result.AppendLine(special);
1585 }
1586 else
1587 {
1588 var p = propertyInfo.GetValue(nestedArrayRecord, null);
1589 /* Leave the c for now at the end, it signifies something useful that still needs to be done i.e. a decoder written */
1590 result.AppendFormat("{0, 30}: {1,-40} [{2}]c" + Environment.NewLine,
1591 propertyInfo.Name,
1592 Utils.BytesToString((byte[])propertyInfo.GetValue(nestedArrayRecord, null)),
1593 propertyInfo.PropertyType.Name);
1594 }
1595 }
1596 result.AppendFormat("{0,32}" + Environment.NewLine, "***");
1597 }
1598 }
1599  
1600 private static void RecursePacketField(FieldInfo fieldInfo, object packet, ref StringBuilder result)
1601 {
1602 object packetDataObject = fieldInfo.GetValue(packet);
1603  
1604 // handle Fields
1605 foreach (FieldInfo packetValueField in fieldInfo.GetValue(packet).GetType().GetFields())
1606 {
1607 string special;
1608 if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + packetValueField.Name,
1609 packetValueField.GetValue(packetDataObject),
1610 out special))
1611 {
1612 result.AppendLine(special);
1613 }
1614 else if (packetValueField.FieldType.IsArray)
1615 {
1616 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
1617 packetValueField.Name,
1618 Utils.BytesToString((byte[])packetValueField.GetValue(packetDataObject)),
1619 /*packetValueField.FieldType.Name*/ "String");
1620 }
1621 else
1622 {
1623 result.AppendFormat("{0,30}: {1,-40} [{2}]" + Environment.NewLine,
1624 packetValueField.Name, packetValueField.GetValue(packetDataObject), packetValueField.FieldType.Name);
1625  
1626 }
1627 }
1628  
1629 // Handle Properties
1630 foreach (PropertyInfo propertyInfo in packetDataObject.GetType().GetProperties())
1631 {
1632 if (propertyInfo.Name.Equals("Length"))
1633 continue;
1634  
1635 string special;
1636 if (SpecialDecoder(packet.GetType().Name + "." + fieldInfo.Name + "." + propertyInfo.Name,
1637 propertyInfo.GetValue(packetDataObject, null),
1638 out special))
1639 {
1640 result.AppendLine(special);
1641 }
1642 else if (propertyInfo.GetValue(packetDataObject, null).GetType() == typeof(byte[]))
1643 {
1644 result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine,
1645 propertyInfo.Name,
1646 Utils.BytesToString((byte[])propertyInfo.GetValue(packetDataObject, null)),
1647 propertyInfo.PropertyType.Name);
1648 }
1649 else
1650 {
1651 result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine,
1652 propertyInfo.Name,
1653 propertyInfo.GetValue(packetDataObject, null),
1654 propertyInfo.PropertyType.Name);
1655 }
1656 }
1657 }
1658  
1659 private static bool SpecialDecoder(string decoderKey, object fieldData, out string result)
1660 {
1661 result = string.Empty;
1662 string[] keys = decoderKey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
1663 string[] keyList = { decoderKey, decoderKey.Replace("Packet", ""), keys[1] + "." + keys[2], keys[2] };
1664 foreach (string key in keyList)
1665 {
1666  
1667 bool ok = true;
1668 if (fieldData is byte[])
1669 {
1670 byte[] fd = (byte[])fieldData;
1671 ok = fd.Length > 0;
1672 if (!ok)
1673 {
1674 // bypass the decoder since we were passed an empty byte array
1675 result = String.Format("{0,30}:", keys[2]);
1676 return true;
1677 }
1678 }
1679  
1680 if (ok && Callbacks.ContainsKey(key)) // fieldname e.g: Plane
1681 {
1682 foreach (CustomPacketDecoder decoder in Callbacks[key])
1683 result = decoder(keys[2], fieldData);
1684 return true;
1685 }
1686 }
1687 return false;
1688 }
1689  
1690 /// <summary>
1691 /// Decode an IMessage object into a beautifully formatted string
1692 /// </summary>
1693 /// <param name="message">The IMessage object</param>
1694 /// <param name="recurseLevel">Recursion level (used for indenting)</param>
1695 /// <returns>A formatted string containing the names and values of the source object</returns>
1696 public static string MessageToString(object message, int recurseLevel)
1697 {
1698 if (message == null)
1699 return String.Empty;
1700  
1701 StringBuilder result = new StringBuilder();
1702 // common/custom types
1703 if (recurseLevel <= 0)
1704 {
1705 result.AppendFormat("Message Type: {0} http://lib.openmetaverse.org/wiki/{0}" + Environment.NewLine, message.GetType().Name);
1706 }
1707 else
1708 {
1709 string pad = " +--".PadLeft(recurseLevel + 3);
1710 result.AppendFormat("{0} {1}" + Environment.NewLine, pad, message.GetType().Name);
1711 }
1712  
1713 recurseLevel++;
1714  
1715 foreach (FieldInfo messageField in message.GetType().GetFields())
1716 {
1717 // an abstract message class
1718 if (messageField.FieldType.IsAbstract)
1719 {
1720 result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel));
1721 }
1722 // a byte array
1723 else if (messageField.GetValue(message) != null && messageField.GetValue(message).GetType() == typeof(Byte[]))
1724 {
1725 result.AppendFormat("{0, 30}:" + Environment.NewLine, messageField.Name);
1726  
1727 result.AppendFormat("{0}" + Environment.NewLine,
1728 Utils.BytesToHexString((byte[])messageField.GetValue(message),
1729 String.Format("{0,30}", "")));
1730 }
1731  
1732 // an array of class objects
1733 else if (messageField.FieldType.IsArray)
1734 {
1735 var messageObjectData = messageField.GetValue(message);
1736 result.AppendFormat("-- {0} --" + Environment.NewLine, messageField.FieldType.Name);
1737 foreach (object nestedArrayObject in messageObjectData as Array)
1738 {
1739 if (nestedArrayObject == null)
1740 {
1741 result.AppendFormat("{0,30}" + Environment.NewLine, "-- null --");
1742 continue;
1743 }
1744 else
1745 {
1746 result.AppendFormat("{0,30}" + Environment.NewLine, "-- " + nestedArrayObject.GetType().Name + " --");
1747 }
1748 foreach (FieldInfo nestedField in nestedArrayObject.GetType().GetFields())
1749 {
1750 if (nestedField.FieldType.IsEnum)
1751 {
1752 result.AppendFormat("{0,30}: {1,-10} {2,-29} [{3}]" + Environment.NewLine,
1753 nestedField.Name,
1754 Enum.Format(nestedField.GetValue(nestedArrayObject).GetType(),
1755 nestedField.GetValue(nestedArrayObject), "D"),
1756 "(" + nestedField.GetValue(nestedArrayObject) + ")",
1757 nestedField.GetValue(nestedArrayObject).GetType().Name);
1758 }
1759 else if (nestedField.FieldType.IsInterface)
1760 {
1761 result.AppendLine(MessageToString(nestedField.GetValue(nestedArrayObject), recurseLevel));
1762 }
1763 else
1764 {
1765 result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine,
1766 nestedField.Name,
1767 nestedField.GetValue(nestedArrayObject),
1768 nestedField.FieldType.Name);
1769 }
1770 }
1771 }
1772 }
1773 else
1774 {
1775 if (messageField.FieldType.IsEnum)
1776 {
1777 result.AppendFormat("{0,30}: {1,-2} {2,-37} [{3}]" + Environment.NewLine,
1778 messageField.Name,
1779 Enum.Format(messageField.GetValue(message).GetType(),
1780 messageField.GetValue(message), "D"),
1781 "(" + messageField.GetValue(message) + ")",
1782 messageField.FieldType.Name);
1783 }
1784 else if (messageField.FieldType.IsInterface)
1785 {
1786 result.AppendLine(MessageToString(messageField.GetValue(message), recurseLevel));
1787 }
1788 else
1789 {
1790 result.AppendFormat("{0, 30}: {1,-40} [{2}]" + Environment.NewLine,
1791 messageField.Name, messageField.GetValue(message), messageField.FieldType.Name);
1792 }
1793 }
1794 }
1795  
1796 return result.ToString();
1797 }
1798 }
1799 }