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