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.IO;
30 using OpenMetaverse;
31  
32 namespace OpenMetaverse
33 {
34 /// <summary>
35 ///
36 /// </summary>
37 public enum FieldType
38 {
39 /// <summary></summary>
40 U8,
41 /// <summary></summary>
42 U16,
43 /// <summary></summary>
44 U32,
45 /// <summary></summary>
46 U64,
47 /// <summary></summary>
48 S8,
49 /// <summary></summary>
50 S16,
51 /// <summary></summary>
52 S32,
53 /// <summary></summary>
54 F32,
55 /// <summary></summary>
56 F64,
57 /// <summary></summary>
58 UUID,
59 /// <summary></summary>
60 BOOL,
61 /// <summary></summary>
62 Vector3,
63 /// <summary></summary>
64 Vector3d,
65 /// <summary></summary>
66 Vector4,
67 /// <summary></summary>
68 Quaternion,
69 /// <summary></summary>
70 IPADDR,
71 /// <summary></summary>
72 IPPORT,
73 /// <summary></summary>
74 Variable,
75 /// <summary></summary>
76 Fixed,
77 /// <summary></summary>
78 Single,
79 /// <summary></summary>
80 Multiple
81 }
82  
83 /// <summary>
84 ///
85 /// </summary>
86 public class MapField : IComparable
87 {
88 /// <summary></summary>
89 public int KeywordPosition;
90 /// <summary></summary>
91 public string Name;
92 /// <summary></summary>
93 public FieldType Type;
94 /// <summary></summary>
95 public int Count;
96  
97 /// <summary>
98 ///
99 /// </summary>
100 /// <param name="obj"></param>
101 /// <returns></returns>
102 public int CompareTo(object obj)
103 {
104 MapField temp = (MapField)obj;
105  
106 if (this.KeywordPosition > temp.KeywordPosition)
107 {
108 return 1;
109 }
110 else
111 {
112 if(temp.KeywordPosition == this.KeywordPosition)
113 {
114 return 0;
115 }
116 else
117 {
118 return -1;
119 }
120 }
121 }
122 }
123  
124 /// <summary>
125 ///
126 /// </summary>
127 public class MapBlock : IComparable
128 {
129 /// <summary></summary>
130 public int KeywordPosition;
131 /// <summary></summary>
132 public string Name;
133 /// <summary></summary>
134 public int Count;
135 /// <summary></summary>
136 public List<MapField> Fields;
137  
138 /// <summary>
139 ///
140 /// </summary>
141 /// <param name="obj"></param>
142 /// <returns></returns>
143 public int CompareTo(object obj)
144 {
145 MapBlock temp = (MapBlock)obj;
146  
147 if (this.KeywordPosition > temp.KeywordPosition)
148 {
149 return 1;
150 }
151 else
152 {
153 if(temp.KeywordPosition == this.KeywordPosition)
154 {
155 return 0;
156 }
157 else
158 {
159 return -1;
160 }
161 }
162 }
163 }
164  
165 /// <summary>
166 ///
167 /// </summary>
168 public class MapPacket
169 {
170 /// <summary></summary>
171 public ushort ID;
172 /// <summary></summary>
173 public string Name;
174 /// <summary></summary>
175 public PacketFrequency Frequency;
176 /// <summary></summary>
177 public bool Trusted;
178 /// <summary></summary>
179 public bool Encoded;
180 /// <summary></summary>
181 public List<MapBlock> Blocks;
182 }
183  
184 /// <summary>
185 ///
186 /// </summary>
187 public class ProtocolManager
188 {
189 /// <summary></summary>
190 public Dictionary<FieldType, int> TypeSizes;
191 /// <summary></summary>
192 public Dictionary<string, int> KeywordPositions;
193 /// <summary></summary>
194 public MapPacket[] LowMaps;
195 /// <summary></summary>
196 public MapPacket[] MediumMaps;
197 /// <summary></summary>
198 public MapPacket[] HighMaps;
199  
200 private GridClient Client;
201  
202 /// <summary>
203 ///
204 /// </summary>
205 /// <param name="mapFile"></param>
206 /// <param name="client"></param>
207 public ProtocolManager(string mapFile, GridClient client)
208 {
209 Client = client;
210  
211 // Initialize the map arrays
212 LowMaps = new MapPacket[65536];
213 MediumMaps = new MapPacket[256];
214 HighMaps = new MapPacket[256];
215  
216 // Build the type size hash table
217 TypeSizes = new Dictionary<FieldType,int>();
218 TypeSizes.Add(FieldType.U8, 1);
219 TypeSizes.Add(FieldType.U16, 2);
220 TypeSizes.Add(FieldType.U32, 4);
221 TypeSizes.Add(FieldType.U64, 8);
222 TypeSizes.Add(FieldType.S8, 1);
223 TypeSizes.Add(FieldType.S16, 2);
224 TypeSizes.Add(FieldType.S32, 4);
225 TypeSizes.Add(FieldType.F32, 4);
226 TypeSizes.Add(FieldType.F64, 8);
227 TypeSizes.Add(FieldType.UUID, 16);
228 TypeSizes.Add(FieldType.BOOL, 1);
229 TypeSizes.Add(FieldType.Vector3, 12);
230 TypeSizes.Add(FieldType.Vector3d, 24);
231 TypeSizes.Add(FieldType.Vector4, 16);
232 TypeSizes.Add(FieldType.Quaternion, 16);
233 TypeSizes.Add(FieldType.IPADDR, 4);
234 TypeSizes.Add(FieldType.IPPORT, 2);
235 TypeSizes.Add(FieldType.Variable, -1);
236 TypeSizes.Add(FieldType.Fixed, -2);
237  
238 KeywordPositions = new Dictionary<string, int>();
239 LoadMapFile(mapFile);
240 }
241  
242 /// <summary>
243 ///
244 /// </summary>
245 /// <param name="command"></param>
246 /// <returns></returns>
247 public MapPacket Command(string command)
248 {
249 foreach (MapPacket map in HighMaps)
250 {
251 if (map != null)
252 {
253 if (command == map.Name)
254 {
255 return map;
256 }
257 }
258 }
259  
260 foreach (MapPacket map in MediumMaps)
261 {
262 if (map != null)
263 {
264 if (command == map.Name)
265 {
266 return map;
267 }
268 }
269 }
270  
271 foreach (MapPacket map in LowMaps)
272 {
273 if (map != null)
274 {
275 if (command == map.Name)
276 {
277 return map;
278 }
279 }
280 }
281  
282 throw new Exception("Cannot find map for command \"" + command + "\"");
283 }
284  
285 /// <summary>
286 ///
287 /// </summary>
288 /// <param name="data"></param>
289 /// <returns></returns>
290 public MapPacket Command(byte[] data)
291 {
292 ushort command;
293  
294 if (data.Length < 5)
295 {
296 return null;
297 }
298  
299 if (data[4] == 0xFF)
300 {
301 if ((byte)data[5] == 0xFF)
302 {
303 // Low frequency
304 command = (ushort)(data[6] * 256 + data[7]);
305 return Command(command, PacketFrequency.Low);
306 }
307 else
308 {
309 // Medium frequency
310 command = (ushort)data[5];
311 return Command(command, PacketFrequency.Medium);
312 }
313 }
314 else
315 {
316 // High frequency
317 command = (ushort)data[4];
318 return Command(command, PacketFrequency.High);
319 }
320 }
321  
322 /// <summary>
323 ///
324 /// </summary>
325 /// <param name="command"></param>
326 /// <param name="frequency"></param>
327 /// <returns></returns>
328 public MapPacket Command(ushort command, PacketFrequency frequency)
329 {
330 switch (frequency)
331 {
332 case PacketFrequency.High:
333 return HighMaps[command];
334 case PacketFrequency.Medium:
335 return MediumMaps[command];
336 case PacketFrequency.Low:
337 return LowMaps[command];
338 }
339  
340 throw new Exception("Cannot find map for command \"" + command + "\" with frequency \"" + frequency + "\"");
341 }
342  
343 /// <summary>
344 ///
345 /// </summary>
346 public void PrintMap()
347 {
348 PrintOneMap(LowMaps, "Low ");
349 PrintOneMap(MediumMaps, "Medium");
350 PrintOneMap(HighMaps, "High ");
351 }
352  
353 /// <summary>
354 ///
355 /// </summary>
356 /// <param name="map"></param>
357 /// <param name="frequency"></param>
358 private void PrintOneMap(MapPacket[] map, string frequency) {
359 int i;
360  
361 for (i = 0; i < map.Length; ++i)
362 {
363 if (map[i] != null)
364 {
365 Console.WriteLine("{0} {1,5} - {2} - {3} - {4}", frequency, i, map[i].Name,
366 map[i].Trusted ? "Trusted" : "Untrusted",
367 map[i].Encoded ? "Unencoded" : "Zerocoded");
368  
369 foreach (MapBlock block in map[i].Blocks)
370 {
371 if (block.Count == -1)
372 {
373 Console.WriteLine("\t{0,4} {1} (Variable)", block.KeywordPosition, block.Name);
374 }
375 else
376 {
377 Console.WriteLine("\t{0,4} {1} ({2})", block.KeywordPosition, block.Name, block.Count);
378 }
379  
380 foreach (MapField field in block.Fields)
381 {
382 Console.WriteLine("\t\t{0,4} {1} ({2} / {3})", field.KeywordPosition, field.Name,
383 field.Type, field.Count);
384 }
385 }
386 }
387 }
388 }
389  
390 /// <summary>
391 ///
392 /// </summary>
393 /// <param name="mapFile"></param>
394 /// <param name="outputFile"></param>
395 public static void DecodeMapFile(string mapFile, string outputFile)
396 {
397 byte magicKey = 0;
398 byte[] buffer = new byte[2048];
399 int nread;
400  
401 try
402 {
403 using (BinaryReader map = new BinaryReader(new FileStream(mapFile, FileMode.Open)))
404 {
405 using (BinaryWriter output = new BinaryWriter(new FileStream(outputFile, FileMode.CreateNew)))
406 {
407 while ((nread = map.Read(buffer, 0, 2048)) != 0)
408 {
409 for (int i = 0; i < nread; ++i)
410 {
411 buffer[i] ^= magicKey;
412 magicKey += 43;
413 }
414  
415 output.Write(buffer, 0, nread);
416 }
417 }
418 }
419 }
420 catch (Exception e)
421 {
422 throw new Exception("Map file error", e);
423 }
424 }
425  
426 /// <summary>
427 ///
428 /// </summary>
429 /// <param name="mapFile"></param>
430 private void LoadMapFile(string mapFile)
431 {
432 ushort low = 1;
433 ushort medium = 1;
434 ushort high = 1;
435  
436 // Load the protocol map file
437 try
438 {
439 using (FileStream map = new FileStream(mapFile, FileMode.Open, FileAccess.Read))
440 {
441 using (StreamReader r = new StreamReader(map))
442 {
443 r.BaseStream.Seek(0, SeekOrigin.Begin);
444 string newline;
445 string trimmedline;
446 bool inPacket = false;
447 bool inBlock = false;
448 MapPacket currentPacket = null;
449 MapBlock currentBlock = null;
450 char[] trimArray = new char[] { ' ', '\t' };
451  
452 // While not at the end of the file
453 while (r.Peek() > -1)
454 {
455 #region ParseMap
456  
457 newline = r.ReadLine();
458 trimmedline = System.Text.RegularExpressions.Regex.Replace(newline, @"\s+", " ");
459 trimmedline = trimmedline.Trim(trimArray);
460  
461 if (!inPacket)
462 {
463 // Outside of all packet blocks
464  
465 if (trimmedline == "{")
466 {
467 inPacket = true;
468 }
469 }
470 else
471 {
472 // Inside of a packet block
473  
474 if (!inBlock)
475 {
476 // Inside a packet block, outside of the blocks
477  
478 if (trimmedline == "{")
479 {
480 inBlock = true;
481 }
482 else if (trimmedline == "}")
483 {
484 // Reached the end of the packet
485 currentPacket.Blocks.Sort();
486 inPacket = false;
487 }
488 else
489 {
490 // The packet header
491 #region ParsePacketHeader
492  
493 // Splice the string in to tokens
494 string[] tokens = trimmedline.Split(new char[] { ' ', '\t' });
495  
496 if (tokens.Length > 3)
497 {
498 //Hash packet name to insure correct keyword ordering
499 KeywordPosition(tokens[0]);
500  
501 if (tokens[1] == "Fixed")
502 {
503 // Remove the leading "0x"
504 if (tokens[2].Substring(0, 2) == "0x")
505 {
506 tokens[2] = tokens[2].Substring(2, tokens[2].Length - 2);
507 }
508  
509 uint fixedID = UInt32.Parse(tokens[2], System.Globalization.NumberStyles.HexNumber);
510 // Truncate the id to a short
511 fixedID ^= 0xFFFF0000;
512 LowMaps[fixedID] = new MapPacket();
513 LowMaps[fixedID].ID = (ushort)fixedID;
514 LowMaps[fixedID].Frequency = PacketFrequency.Low;
515 LowMaps[fixedID].Name = tokens[0];
516 LowMaps[fixedID].Trusted = (tokens[3] == "Trusted");
517 LowMaps[fixedID].Encoded = (tokens[4] == "Zerocoded");
518 LowMaps[fixedID].Blocks = new List<MapBlock>();
519  
520 currentPacket = LowMaps[fixedID];
521 }
522 else if (tokens[1] == "Low")
523 {
524 LowMaps[low] = new MapPacket();
525 LowMaps[low].ID = low;
526 LowMaps[low].Frequency = PacketFrequency.Low;
527 LowMaps[low].Name = tokens[0];
528 LowMaps[low].Trusted = (tokens[2] == "Trusted");
529 LowMaps[low].Encoded = (tokens[3] == "Zerocoded");
530 LowMaps[low].Blocks = new List<MapBlock>();
531  
532 currentPacket = LowMaps[low];
533  
534 low++;
535 }
536 else if (tokens[1] == "Medium")
537 {
538 MediumMaps[medium] = new MapPacket();
539 MediumMaps[medium].ID = medium;
540 MediumMaps[medium].Frequency = PacketFrequency.Medium;
541 MediumMaps[medium].Name = tokens[0];
542 MediumMaps[medium].Trusted = (tokens[2] == "Trusted");
543 MediumMaps[medium].Encoded = (tokens[3] == "Zerocoded");
544 MediumMaps[medium].Blocks = new List<MapBlock>();
545  
546 currentPacket = MediumMaps[medium];
547  
548 medium++;
549 }
550 else if (tokens[1] == "High")
551 {
552 HighMaps[high] = new MapPacket();
553 HighMaps[high].ID = high;
554 HighMaps[high].Frequency = PacketFrequency.High;
555 HighMaps[high].Name = tokens[0];
556 HighMaps[high].Trusted = (tokens[2] == "Trusted");
557 HighMaps[high].Encoded = (tokens[3] == "Zerocoded");
558 HighMaps[high].Blocks = new List<MapBlock>();
559  
560 currentPacket = HighMaps[high];
561  
562 high++;
563 }
564 else
565 {
566 Logger.Log("Unknown packet frequency", Helpers.LogLevel.Error, Client);
567 }
568 }
569  
570 #endregion
571 }
572 }
573 else
574 {
575 if (trimmedline.Length > 0 && trimmedline.Substring(0, 1) == "{")
576 {
577 // A field
578 #region ParseField
579  
580 MapField field = new MapField();
581  
582 // Splice the string in to tokens
583 string[] tokens = trimmedline.Split(new char[] { ' ', '\t' });
584  
585 field.Name = tokens[1];
586 field.KeywordPosition = KeywordPosition(field.Name);
587 field.Type = (FieldType)Enum.Parse(typeof(FieldType), tokens[2], true);
588  
589 if (tokens[3] != "}")
590 {
591 field.Count = Int32.Parse(tokens[3]);
592 }
593 else
594 {
595 field.Count = 1;
596 }
597  
598 // Save this field to the current block
599 currentBlock.Fields.Add(field);
600  
601 #endregion
602 }
603 else if (trimmedline == "}")
604 {
605 currentBlock.Fields.Sort();
606 inBlock = false;
607 }
608 else if (trimmedline.Length != 0 && trimmedline.Substring(0, 2) != "//")
609 {
610 // The block header
611 #region ParseBlockHeader
612  
613 currentBlock = new MapBlock();
614  
615 // Splice the string in to tokens
616 string[] tokens = trimmedline.Split(new char[] { ' ', '\t' });
617  
618 currentBlock.Name = tokens[0];
619 currentBlock.KeywordPosition = KeywordPosition(currentBlock.Name);
620 currentBlock.Fields = new List<MapField>();
621 currentPacket.Blocks.Add(currentBlock);
622  
623 if (tokens[1] == "Single")
624 {
625 currentBlock.Count = 1;
626 }
627 else if (tokens[1] == "Multiple")
628 {
629 currentBlock.Count = Int32.Parse(tokens[2]);
630 }
631 else if (tokens[1] == "Variable")
632 {
633 currentBlock.Count = -1;
634 }
635 else
636 {
637 Logger.Log("Unknown block frequency", Helpers.LogLevel.Error, Client);
638 }
639  
640 #endregion
641 }
642 }
643 }
644  
645 #endregion
646 }
647 }
648  
649 }
650 }
651 catch (Exception e)
652 {
653 throw new Exception("Map file parsing error", e); ;
654 }
655 }
656  
657 private int KeywordPosition(string keyword)
658 {
659 if (KeywordPositions.ContainsKey(keyword))
660 {
661 return KeywordPositions[keyword];
662 }
663  
664 int hash = 0;
665 for (int i = 1; i < keyword.Length; i++)
666 {
667 hash = (hash + (int)(keyword[i])) * 2;
668 }
669 hash *= 2;
670 hash &= 0x1FFF;
671  
672 int startHash = hash;
673  
674 while (KeywordPositions.ContainsValue(hash))
675 {
676 hash++;
677 hash &= 0x1FFF;
678 if (hash == startHash)
679 {
680 //Give up looking, went through all values and they were all taken.
681 throw new Exception("All hash values are taken. Failed to add keyword: " + keyword);
682 }
683 }
684  
685 KeywordPositions[keyword] = hash;
686 return hash;
687 }
688 }
689 }