aboutsummaryrefslogtreecommitdiff
path: root/src/dtf/WixToolset.Dtf.WindowsInstaller.Package/InstallPath.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dtf/WixToolset.Dtf.WindowsInstaller.Package/InstallPath.cs1073
1 files changed, 1073 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.WindowsInstaller.Package/InstallPath.cs b/src/dtf/WixToolset.Dtf.WindowsInstaller.Package/InstallPath.cs
new file mode 100644
index 00000000..e3ba81b5
--- /dev/null
+++ b/src/dtf/WixToolset.Dtf.WindowsInstaller.Package/InstallPath.cs
@@ -0,0 +1,1073 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Dtf.WindowsInstaller.Package
4{
5 using System;
6 using System.IO;
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.Globalization;
10
11 /// <summary>
12 /// Represents the installation path of a file or directory from an installer product database.
13 /// </summary>
14 public class InstallPath
15 {
16 /// <summary>
17 /// Creates a new InstallPath, specifying a filename.
18 /// </summary>
19 /// <param name="name">The name of the file or directory. Not a full path.</param>
20 public InstallPath(string name) : this(name, false) { }
21
22 /// <summary>
23 /// Creates a new InstallPath, parsing out either the short or long filename.
24 /// </summary>
25 /// <param name="name">The name of the file or directory, in short|long syntax for a filename
26 /// or targetshort|targetlong:sourceshort|sourcelong syntax for a directory.</param>
27 /// <param name="useShortNames">true to parse the short part of the combined filename; false to parse the long part</param>
28 public InstallPath(string name, bool useShortNames)
29 {
30 if(name == null)
31 {
32 throw new ArgumentNullException();
33 }
34 this.parentPath = null;
35 ParseName(name, useShortNames);
36 }
37
38 private void ParseName(string name, bool useShortNames)
39 {
40 string[] parse = name.Split(new char[] { ':' }, 3);
41 if(parse.Length == 3)
42 {
43 // Syntax was targetshort:sourceshort|targetlong:sourcelong.
44 // Chnage it to targetshort|targetlong:sourceshort|sourcelong.
45 parse = name.Split(new char[] { ':', '|' }, 4);
46 if(parse.Length == 4)
47 parse = new string[] { parse[0] + '|' + parse[2], parse[1] + '|' + parse[3] };
48 else
49 parse = new string[] { parse[0] + '|' + parse[1], parse[1] + '|' + parse[2] };
50 }
51 string targetName = parse[0];
52 string sourceName = (parse.Length == 2 ? parse[1] : parse[0]);
53 parse = targetName.Split(new char[] { '|' }, 2);
54 if(parse.Length == 2) targetName = (useShortNames ? parse[0] : parse[1]);
55 parse = sourceName.Split(new char[] { '|' }, 2);
56 if(parse.Length == 2) sourceName = (useShortNames ? parse[0] : parse[1]);
57
58 this.SourceName = sourceName;
59 this.TargetName = targetName;
60 }
61
62 /// <summary>
63 /// Gets the path of the parent directory.
64 /// </summary>
65 public InstallPath ParentPath
66 {
67 get
68 {
69 return parentPath;
70 }
71 }
72 internal void SetParentPath(InstallPath value)
73 {
74 parentPath = value;
75 ResetSourcePath();
76 ResetTargetPath();
77 }
78 private InstallPath parentPath;
79
80 /// <summary>
81 /// Gets the set of child paths if this InstallPath object represents a a directory.
82 /// </summary>
83 public InstallPathCollection ChildPaths
84 {
85 get
86 {
87 if(childPaths == null)
88 {
89 childPaths = new InstallPathCollection(this);
90 }
91 return childPaths;
92 }
93 }
94 private InstallPathCollection childPaths;
95
96 /// <summary>
97 /// Gets or sets the source name of the InstallPath.
98 /// </summary>
99 public string SourceName
100 {
101 get
102 {
103 return sourceName;
104 }
105 set
106 {
107 if(value == null)
108 {
109 throw new ArgumentNullException();
110 }
111 sourceName = value;
112 ResetSourcePath();
113 }
114 }
115 private string sourceName;
116
117 /// <summary>
118 /// Gets or sets the target name of the install path.
119 /// </summary>
120 public string TargetName
121 {
122 get
123 {
124 return targetName;
125 }
126 set
127 {
128 if(value == null)
129 {
130 throw new ArgumentNullException();
131 }
132 targetName = value;
133 ResetTargetPath();
134 }
135 }
136 private string targetName;
137
138 /// <summary>
139 /// Gets the full source path.
140 /// </summary>
141 public string SourcePath
142 {
143 get
144 {
145 if(sourcePath == null)
146 {
147 if(parentPath != null)
148 {
149 sourcePath = (sourceName.Equals(".") ? parentPath.SourcePath
150 : Path.Combine(parentPath.SourcePath, sourceName));
151 }
152 else
153 {
154 sourcePath = sourceName;
155 }
156 }
157 return sourcePath;
158 }
159 set
160 {
161 ResetSourcePath();
162 sourcePath = value;
163 }
164 }
165 private string sourcePath;
166
167 /// <summary>
168 /// Gets the full target path.
169 /// </summary>
170 public string TargetPath
171 {
172 get
173 {
174 if(targetPath == null)
175 {
176 if(parentPath != null)
177 {
178 targetPath = (targetName.Equals(".") ? parentPath.TargetPath
179 : Path.Combine(parentPath.TargetPath, targetName));
180 }
181 else
182 {
183 targetPath = targetName;
184 }
185 }
186 return targetPath;
187 }
188 set
189 {
190 ResetTargetPath();
191 targetPath = value;
192 }
193 }
194 private string targetPath;
195
196 private void ResetSourcePath()
197 {
198 if(sourcePath != null)
199 {
200 sourcePath = null;
201 if(childPaths != null)
202 {
203 foreach(InstallPath ip in childPaths)
204 {
205 ip.ResetSourcePath();
206 }
207 }
208 }
209 }
210
211 private void ResetTargetPath()
212 {
213 if(targetPath != null)
214 {
215 targetPath = null;
216 if(childPaths != null)
217 {
218 foreach(InstallPath ip in childPaths)
219 {
220 ip.ResetTargetPath();
221 }
222 }
223 }
224 }
225
226 /// <summary>
227 /// Gets the full source path.
228 /// </summary>
229 /// <returns><see cref="SourcePath"/></returns>
230 public override String ToString()
231 {
232 return SourcePath;
233 }
234 }
235
236 /// <summary>
237 /// Represents a collection of InstallPaths that are the child paths of the same parent directory.
238 /// </summary>
239 public class InstallPathCollection : IList<InstallPath>
240 {
241 private InstallPath parentPath;
242 private List<InstallPath> items;
243
244 internal InstallPathCollection(InstallPath parentPath)
245 {
246 this.parentPath = parentPath;
247 this.items = new List<InstallPath>();
248 }
249
250 /// <summary>
251 /// Gets or sets the element at the specified index.
252 /// </summary>
253 public InstallPath this[int index]
254 {
255 get
256 {
257 return this.items[index];
258 }
259 set
260 {
261 this.OnSet(this.items[index], value);
262 this.items[index] = value;
263 }
264 }
265
266 /// <summary>
267 /// Adds a new child path to the collection.
268 /// </summary>
269 /// <param name="item">The InstallPath to add.</param>
270 public void Add(InstallPath item)
271 {
272 this.OnInsert(item);
273 this.items.Add(item);
274 }
275
276 /// <summary>
277 /// Removes a child path to the collection.
278 /// </summary>
279 /// <param name="item">The InstallPath to remove.</param>
280 public bool Remove(InstallPath item)
281 {
282 int index = this.items.IndexOf(item);
283 if (index >= 0)
284 {
285 this.OnRemove(item);
286 this.items.RemoveAt(index);
287 return true;
288 }
289 else
290 {
291 return false;
292 }
293 }
294
295 /// <summary>
296 /// Gets the index of a child path in the collection.
297 /// </summary>
298 /// <param name="item">The InstallPath to search for.</param>
299 /// <returns>The index of the item, or -1 if not found.</returns>
300 public int IndexOf(InstallPath item)
301 {
302 return this.items.IndexOf(item);
303 }
304
305 /// <summary>
306 /// Inserts a child path into the collection.
307 /// </summary>
308 /// <param name="index">The insertion index.</param>
309 /// <param name="item">The InstallPath to insert.</param>
310 public void Insert(int index, InstallPath item)
311 {
312 this.OnInsert(item);
313 this.items.Insert(index, item);
314 }
315
316 /// <summary>
317 /// Tests if the collection contains a child path.
318 /// </summary>
319 /// <param name="item">The InstallPath to search for.</param>
320 /// <returns>true if the item is found; false otherwise</returns>
321 public bool Contains(InstallPath item)
322 {
323 return this.items.Contains(item);
324 }
325
326 /// <summary>
327 /// Copies the collection into an array.
328 /// </summary>
329 /// <param name="array">The array to copy into.</param>
330 /// <param name="index">The starting index in the destination array.</param>
331 public void CopyTo(InstallPath[] array, int index)
332 {
333 this.items.CopyTo(array, index);
334 }
335
336 private void OnInsert(InstallPath item)
337 {
338 if (item.ParentPath != null)
339 {
340 item.ParentPath.ChildPaths.Remove(item);
341 }
342
343 item.SetParentPath(this.parentPath);
344 }
345
346 private void OnRemove(InstallPath item)
347 {
348 item.SetParentPath(null);
349 }
350
351 private void OnSet(InstallPath oldItem, InstallPath newItem)
352 {
353 this.OnRemove(oldItem);
354 this.OnInsert(newItem);
355 }
356
357 /// <summary>
358 /// Removes an item from the collection.
359 /// </summary>
360 /// <param name="index">The index of the item to remove.</param>
361 public void RemoveAt(int index)
362 {
363 this.OnRemove(this[index]);
364 this.items.RemoveAt(index);
365 }
366
367 /// <summary>
368 /// Removes all items from the collection.
369 /// </summary>
370 public void Clear()
371 {
372 foreach (InstallPath item in this)
373 {
374 this.OnRemove(item);
375 }
376
377 this.items.Clear();
378 }
379
380 /// <summary>
381 /// Gets the number of items in the collection.
382 /// </summary>
383 public int Count
384 {
385 get
386 {
387 return this.items.Count;
388 }
389 }
390
391 bool ICollection<InstallPath>.IsReadOnly
392 {
393 get
394 {
395 return false;
396 }
397 }
398
399 /// <summary>
400 /// Gets an enumerator over all items in the collection.
401 /// </summary>
402 /// <returns>An enumerator for the collection.</returns>
403 public IEnumerator<InstallPath> GetEnumerator()
404 {
405 return this.items.GetEnumerator();
406 }
407
408 IEnumerator IEnumerable.GetEnumerator()
409 {
410 return ((IEnumerable<InstallPath>) this).GetEnumerator();
411 }
412 }
413
414 /// <summary>
415 /// Represents a mapping of install paths for all directories, components, or files in
416 /// an installation database.
417 /// </summary>
418 public class InstallPathMap : IDictionary<string, InstallPath>
419 {
420 /// <summary>
421 /// Builds a mapping from File keys to installation paths.
422 /// </summary>
423 /// <param name="db">Installation database.</param>
424 /// <param name="componentPathMap">Component mapping returned by <see cref="BuildComponentPathMap"/>.</param>
425 /// <param name="useShortNames">true to use short file names; false to use long names</param>
426 /// <returns>An InstallPathMap with the described mapping.</returns>
427 public static InstallPathMap BuildFilePathMap(Database db, InstallPathMap componentPathMap,
428 bool useShortNames)
429 {
430 if(db == null)
431 {
432 throw new ArgumentNullException("db");
433 }
434
435 if(componentPathMap == null)
436 {
437 componentPathMap = BuildComponentPathMap(db, BuildDirectoryPathMap(db, useShortNames));
438 }
439
440 InstallPathMap filePathMap = new InstallPathMap();
441
442 using (View fileView = db.OpenView("SELECT `File`, `Component_`, `FileName` FROM `File`"))
443 {
444 fileView.Execute();
445
446 foreach (Record fileRec in fileView)
447 {
448 using (fileRec)
449 {
450 string file = (string) fileRec[1];
451 string comp = (string) fileRec[2];
452 string fileName = (string) fileRec[3];
453
454 InstallPath compPath = (InstallPath) componentPathMap[comp];
455 if(compPath != null)
456 {
457 InstallPath filePath = new InstallPath(fileName, useShortNames);
458 compPath.ChildPaths.Add(filePath);
459 filePathMap[file] = filePath;
460 }
461 }
462 }
463 }
464
465 return filePathMap;
466 }
467
468 /// <summary>
469 /// Builds a mapping from Component keys to installation paths.
470 /// </summary>
471 /// <param name="db">Installation database.</param>
472 /// <param name="directoryPathMap">Directory mapping returned by
473 /// <see cref="BuildDirectoryPathMap(Database,bool)"/>.</param>
474 /// <returns>An InstallPathMap with the described mapping.</returns>
475 public static InstallPathMap BuildComponentPathMap(Database db, InstallPathMap directoryPathMap)
476 {
477 if(db == null)
478 {
479 throw new ArgumentNullException("db");
480 }
481
482 InstallPathMap compPathMap = new InstallPathMap();
483
484 using (View compView = db.OpenView("SELECT `Component`, `Directory_` FROM `Component`"))
485 {
486 compView.Execute();
487
488 foreach (Record compRec in compView)
489 {
490 using (compRec)
491 {
492 string comp = (string) compRec[1];
493 InstallPath dirPath = (InstallPath) directoryPathMap[(string) compRec[2]];
494
495 if (dirPath != null)
496 {
497 compPathMap[comp] = dirPath;
498 }
499 }
500 }
501 }
502
503 return compPathMap;
504 }
505
506 /// <summary>
507 /// Builds a mapping from Directory keys to installation paths.
508 /// </summary>
509 /// <param name="db">Installation database.</param>
510 /// <param name="useShortNames">true to use short directory names; false to use long names</param>
511 /// <returns>An InstallPathMap with the described mapping.</returns>
512 public static InstallPathMap BuildDirectoryPathMap(Database db, bool useShortNames)
513 {
514 return BuildDirectoryPathMap(db, useShortNames, null, null);
515 }
516
517 /// <summary>
518 /// Builds a mapping of Directory keys to directory paths, specifying root directories
519 /// for the source and target paths.
520 /// </summary>
521 /// <param name="db">Database containing the Directory table.</param>
522 /// <param name="useShortNames">true to use short directory names; false to use long names</param>
523 /// <param name="sourceRootDir">The root directory path of all source paths, or null to leave them relative.</param>
524 /// <param name="targetRootDir">The root directory path of all source paths, or null to leave them relative.</param>
525 /// <returns>An InstallPathMap with the described mapping.</returns>
526 public static InstallPathMap BuildDirectoryPathMap(Database db, bool useShortNames,
527 string sourceRootDir, string targetRootDir)
528 {
529 if(db == null)
530 {
531 throw new ArgumentNullException("db");
532 }
533
534 if(sourceRootDir == null) sourceRootDir = "";
535 if(targetRootDir == null) targetRootDir = "";
536
537 InstallPathMap dirMap = new InstallPathMap();
538 IDictionary dirTreeMap = new Hashtable();
539
540 using (View dirView = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
541 {
542 dirView.Execute();
543
544 foreach (Record dirRec in dirView) using (dirRec)
545 {
546 string key = (string) dirRec[1];
547 string parentKey = (string) dirRec[2];
548 InstallPath dir = new InstallPath((string) dirRec[3], useShortNames);
549
550 dirMap[key] = dir;
551
552 InstallPathMap siblingDirs = (InstallPathMap) dirTreeMap[parentKey];
553 if (siblingDirs == null)
554 {
555 siblingDirs = new InstallPathMap();
556 dirTreeMap[parentKey] = siblingDirs;
557 }
558 siblingDirs.Add(key, dir);
559 }
560 }
561
562 foreach (KeyValuePair<string, InstallPath> entry in (InstallPathMap) dirTreeMap[""])
563 {
564 string key = (string) entry.Key;
565 InstallPath dir = (InstallPath) entry.Value;
566 LinkSubdirectories(key, dir, dirTreeMap);
567 }
568
569 InstallPath targetDirPath = (InstallPath) dirMap["TARGETDIR"];
570 if(targetDirPath != null)
571 {
572 targetDirPath.SourcePath = sourceRootDir;
573 targetDirPath.TargetPath = targetRootDir;
574 }
575
576 return dirMap;
577 }
578
579 private static void LinkSubdirectories(string key, InstallPath dir, IDictionary dirTreeMap)
580 {
581 InstallPathMap subDirs = (InstallPathMap) dirTreeMap[key];
582 if(subDirs != null)
583 {
584 foreach (KeyValuePair<string, InstallPath> entry in subDirs)
585 {
586 string subKey = (string) entry.Key;
587 InstallPath subDir = (InstallPath) entry.Value;
588 dir.ChildPaths.Add(subDir);
589 LinkSubdirectories(subKey, subDir, dirTreeMap);
590 }
591 }
592 }
593
594 private Dictionary<string, InstallPath> items;
595
596 /// <summary>
597 /// Creates a new empty InstallPathMap.
598 /// </summary>
599 public InstallPathMap()
600 {
601 this.items = new Dictionary<string,InstallPath>(StringComparer.Ordinal);
602 }
603
604 /// <summary>
605 /// Gets a mapping from keys to source paths.
606 /// </summary>
607 public IDictionary<string, string> SourcePaths
608 {
609 get
610 {
611 return new SourcePathMap(this);
612 }
613 }
614
615 /// <summary>
616 /// Gets a mapping from keys to target paths.
617 /// </summary>
618 public IDictionary<string, string> TargetPaths
619 {
620 get
621 {
622 return new TargetPathMap(this);
623 }
624 }
625
626 /// <summary>
627 /// Gets or sets an install path for a direcotry, component, or file key.
628 /// </summary>
629 /// <param name="key">Depending on the type of InstallPathMap, this is the primary key from the
630 /// either the Directory, Component, or File table.</param>
631 /// <remarks>
632 /// Changing an install path does not modify the Database used to generate this InstallPathMap.
633 /// </remarks>
634 public InstallPath this[string key]
635 {
636 get
637 {
638 InstallPath value = null;
639 this.items.TryGetValue(key, out value);
640 return value;
641 }
642 set
643 {
644 this.items[key] = value;
645 }
646 }
647
648 /// <summary>
649 /// Gets the collection of keys in the InstallPathMap. Depending on the type of InstallPathMap,
650 /// they are all directory, component, or file key strings.
651 /// </summary>
652 public ICollection<string> Keys
653 {
654 get
655 {
656 return this.items.Keys;
657 }
658 }
659
660 /// <summary>
661 /// Gets the collection of InstallPath values in the InstallPathMap.
662 /// </summary>
663 public ICollection<InstallPath> Values
664 {
665 get
666 {
667 return this.items.Values;
668 }
669 }
670
671 /// <summary>
672 /// Sets an install path for a direcotry, component, or file key.
673 /// </summary>
674 /// <param name="key">Depending on the type of InstallPathMap, this is the primary key from the
675 /// either the Directory, Component, or File table.</param>
676 /// <param name="installPath">The install path of the key item.</param>
677 /// <remarks>
678 /// Changing an install path does not modify the Database used to generate this InstallPathMap.
679 /// </remarks>
680 public void Add(string key, InstallPath installPath)
681 {
682 this.items.Add(key, installPath);
683 }
684
685 /// <summary>
686 /// Removes an install path from the map.
687 /// </summary>
688 /// <param name="key">Depending on the type of InstallPathMap, this is the primary key from the
689 /// either the Directory, Component, or File table.</param>
690 /// <returns>true if the item was removed, false if it did not exist</returns>
691 /// <remarks>
692 /// Changing an install path does not modify the Database used to generate this InstallPathMap.
693 /// </remarks>
694 public bool Remove(string key)
695 {
696 return this.items.Remove(key);
697 }
698
699 /// <summary>
700 /// Tests whether a direcotry, component, or file key exists in the map.
701 /// </summary>
702 /// <param name="key">Depending on the type of InstallPathMap, this is the primary key from the
703 /// either the Directory, Component, or File table.</param>
704 /// <returns>true if the key is found; false otherwise</returns>
705 public bool ContainsKey(string key)
706 {
707 return this.items.ContainsKey(key);
708 }
709
710 /*
711 public override string ToString()
712 {
713 System.Text.StringBuilder buf = new System.Text.StringBuilder();
714 foreach(KeyValuePair<string, InstallPath> entry in this)
715 {
716 buf.AppendFormat("{0}={1}", entry.Key, entry.Value);
717 buf.Append("\n");
718 }
719 return buf.ToString();
720 }
721 */
722
723 /// <summary>
724 /// Attempts to get a value from the dictionary.
725 /// </summary>
726 /// <param name="key">The key to lookup.</param>
727 /// <param name="value">Receives the value, or null if they key was not found.</param>
728 /// <returns>True if the value was found, else false.</returns>
729 public bool TryGetValue(string key, out InstallPath value)
730 {
731 return this.items.TryGetValue(key, out value);
732 }
733
734 void ICollection<KeyValuePair<string, InstallPath>>.Add(KeyValuePair<string, InstallPath> item)
735 {
736 ((ICollection<KeyValuePair<string, InstallPath>>) this.items).Add(item);
737 }
738
739 /// <summary>
740 /// Removes all entries from the dictionary.
741 /// </summary>
742 public void Clear()
743 {
744 this.items.Clear();
745 }
746
747 bool ICollection<KeyValuePair<string, InstallPath>>.Contains(KeyValuePair<string, InstallPath> item)
748 {
749 return ((ICollection<KeyValuePair<string, InstallPath>>) this.items).Contains(item);
750 }
751
752 void ICollection<KeyValuePair<string, InstallPath>>.CopyTo(KeyValuePair<string, InstallPath>[] array, int arrayIndex)
753 {
754 ((ICollection<KeyValuePair<string, InstallPath>>) this.items).CopyTo(array, arrayIndex);
755 }
756
757 /// <summary>
758 /// Gets the number of entries in the dictionary.
759 /// </summary>
760 public int Count
761 {
762 get
763 {
764 return this.items.Count;
765 }
766 }
767
768 bool ICollection<KeyValuePair<string, InstallPath>>.IsReadOnly
769 {
770 get
771 {
772 return false;
773 }
774 }
775
776 bool ICollection<KeyValuePair<string, InstallPath>>.Remove(KeyValuePair<string, InstallPath> item)
777 {
778 return ((ICollection<KeyValuePair<string, InstallPath>>) this.items).Remove(item);
779 }
780
781 /// <summary>
782 /// Gets an enumerator over all entries in the dictionary.
783 /// </summary>
784 /// <returns>An enumerator for the dictionary.</returns>
785 public IEnumerator<KeyValuePair<string, InstallPath>> GetEnumerator()
786 {
787 return this.items.GetEnumerator();
788 }
789
790 IEnumerator IEnumerable.GetEnumerator()
791 {
792 return this.items.GetEnumerator();
793 }
794 }
795
796 internal class SourcePathMap : IDictionary<string, string>
797 {
798 private const string RO_MSG =
799 "The SourcePathMap collection is read-only. " +
800 "Modify the InstallPathMap instead.";
801
802 private InstallPathMap map;
803
804 internal SourcePathMap(InstallPathMap map)
805 {
806 this.map = map;
807 }
808
809 public void Add(string key, string value)
810 {
811 throw new InvalidOperationException(RO_MSG);
812 }
813
814 public bool ContainsKey(string key)
815 {
816 return this.map.ContainsKey(key);
817 }
818
819 public ICollection<string> Keys
820 {
821 get
822 {
823 return this.map.Keys;
824 }
825 }
826
827 public bool Remove(string key)
828 {
829 throw new InvalidOperationException(RO_MSG);
830 }
831
832 public bool TryGetValue(string key, out string value)
833 {
834 InstallPath installPath;
835 if (this.map.TryGetValue(key, out installPath))
836 {
837 value = installPath.SourcePath;
838 return true;
839 }
840 else
841 {
842 value = null;
843 return false;
844 }
845 }
846
847 public ICollection<string> Values
848 {
849 get
850 {
851 List<string> values = new List<string>(this.Count);
852 foreach (KeyValuePair<string, InstallPath> entry in this.map)
853 {
854 values.Add(entry.Value.SourcePath);
855 }
856 return values;
857 }
858 }
859
860 public string this[string key]
861 {
862 get
863 {
864 string value = null;
865 this.TryGetValue(key, out value);
866 return value;
867 }
868 set
869 {
870 throw new InvalidOperationException(RO_MSG);
871 }
872 }
873
874 public void Add(KeyValuePair<string, string> item)
875 {
876 throw new InvalidOperationException(RO_MSG);
877 }
878
879 public void Clear()
880 {
881 throw new InvalidOperationException(RO_MSG);
882 }
883
884 public bool Contains(KeyValuePair<string, string> item)
885 {
886 string value = this[item.Key];
887 return value == item.Value;
888 }
889
890 public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
891 {
892 foreach (KeyValuePair<string, string> entry in this)
893 {
894 array[arrayIndex] = entry;
895 arrayIndex++;
896 }
897 }
898
899 public int Count
900 {
901 get
902 {
903 return this.map.Count;
904 }
905 }
906
907 public bool IsReadOnly
908 {
909 get
910 {
911 return true;
912 }
913 }
914
915 public bool Remove(KeyValuePair<string, string> item)
916 {
917 throw new InvalidOperationException(RO_MSG);
918 }
919
920 public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
921 {
922 foreach (KeyValuePair<string, InstallPath> entry in this.map)
923 {
924 yield return new KeyValuePair<string, string>(
925 entry.Key, entry.Value.SourcePath);
926 }
927 }
928
929 IEnumerator IEnumerable.GetEnumerator()
930 {
931 return this.GetEnumerator();
932 }
933 }
934
935 internal class TargetPathMap : IDictionary<string, string>
936 {
937 private const string RO_MSG =
938 "The TargetPathMap collection is read-only. " +
939 "Modify the InstallPathMap instead.";
940
941 private InstallPathMap map;
942
943 internal TargetPathMap(InstallPathMap map)
944 {
945 this.map = map;
946 }
947
948 public void Add(string key, string value)
949 {
950 throw new InvalidOperationException(RO_MSG);
951 }
952
953 public bool ContainsKey(string key)
954 {
955 return this.map.ContainsKey(key);
956 }
957
958 public ICollection<string> Keys
959 {
960 get
961 {
962 return this.map.Keys;
963 }
964 }
965
966 public bool Remove(string key)
967 {
968 throw new InvalidOperationException(RO_MSG);
969 }
970
971 public bool TryGetValue(string key, out string value)
972 {
973 InstallPath installPath;
974 if (this.map.TryGetValue(key, out installPath))
975 {
976 value = installPath.TargetPath;
977 return true;
978 }
979 else
980 {
981 value = null;
982 return false;
983 }
984 }
985
986 public ICollection<string> Values
987 {
988 get
989 {
990 List<string> values = new List<string>(this.Count);
991 foreach (KeyValuePair<string, InstallPath> entry in this.map)
992 {
993 values.Add(entry.Value.TargetPath);
994 }
995 return values;
996 }
997 }
998
999 public string this[string key]
1000 {
1001 get
1002 {
1003 string value = null;
1004 this.TryGetValue(key, out value);
1005 return value;
1006 }
1007 set
1008 {
1009 throw new InvalidOperationException(RO_MSG);
1010 }
1011 }
1012
1013 public void Add(KeyValuePair<string, string> item)
1014 {
1015 throw new InvalidOperationException(RO_MSG);
1016 }
1017
1018 public void Clear()
1019 {
1020 throw new InvalidOperationException(RO_MSG);
1021 }
1022
1023 public bool Contains(KeyValuePair<string, string> item)
1024 {
1025 string value = this[item.Key];
1026 return value == item.Value;
1027 }
1028
1029 public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
1030 {
1031 foreach (KeyValuePair<string, string> entry in this)
1032 {
1033 array[arrayIndex] = entry;
1034 arrayIndex++;
1035 }
1036 }
1037
1038 public int Count
1039 {
1040 get
1041 {
1042 return this.map.Count;
1043 }
1044 }
1045
1046 public bool IsReadOnly
1047 {
1048 get
1049 {
1050 return true;
1051 }
1052 }
1053
1054 public bool Remove(KeyValuePair<string, string> item)
1055 {
1056 throw new InvalidOperationException(RO_MSG);
1057 }
1058
1059 public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
1060 {
1061 foreach (KeyValuePair<string, InstallPath> entry in this.map)
1062 {
1063 yield return new KeyValuePair<string, string>(
1064 entry.Key, entry.Value.TargetPath);
1065 }
1066 }
1067
1068 IEnumerator IEnumerable.GetEnumerator()
1069 {
1070 return this.GetEnumerator();
1071 }
1072 }
1073}