[runtime] Fix test_op_il_seq_point in amd64.
[mono.git] / mcs / class / WindowsBase / System.IO.Packaging / PackagePart.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2007 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Chris Toshok (toshok@ximian.com)
24 //  Alan McGovern (amcgovern@novell.com)
25 //
26
27 using System;
28 using System.Collections.Generic;
29 using System.IO;
30 using System.Xml;
31
32 namespace System.IO.Packaging {
33
34         public abstract class PackagePart
35         {
36                 string contentType;
37                 
38                 internal bool IsRelationship { get; set; }
39                 
40                 int relationshipId;
41                 Dictionary<string, PackageRelationship> relationships;
42                 PackageRelationshipCollection relationshipsCollection = new PackageRelationshipCollection ();
43                 
44                 Dictionary<string, PackageRelationship> Relationships {
45                         get {
46                                 if (relationships == null) {
47                                         relationships = new Dictionary<string, PackageRelationship> (StringComparer.OrdinalIgnoreCase);
48                                         if (Package.PartExists (RelationshipsPartUri))
49                                                 using (Stream s = Package.GetPart (RelationshipsPartUri).GetStream ())
50                                                         LoadRelationships (relationships, s);
51                                 }
52
53                                 return relationships;
54                         }
55                 }
56                 Stream PartStream { get; set;  }
57
58                 internal Uri RelationshipsPartUri {
59                         get; set;
60                 }
61                 
62                 protected PackagePart (Package package, Uri partUri)
63                         : this(package, partUri, null)
64                 {
65                         
66                 }
67
68                 protected internal PackagePart (Package package, Uri partUri, string contentType)
69                         : this (package, partUri, contentType, CompressionOption.Normal)
70                 {
71                         
72                 }
73
74                 protected internal PackagePart (Package package, Uri partUri, string contentType, CompressionOption compressionOption)
75                 {
76                         Check.Package (package);
77                         Check.PartUri (partUri);
78                         Check.ContentTypeIsValid (contentType);
79
80                         Package = package;
81                         Uri = partUri;
82                         ContentType = contentType;
83                         CompressionOption = compressionOption;
84                         RelationshipsPartUri = PackUriHelper.GetRelationshipPartUri(Uri);
85                 }
86
87                 public CompressionOption CompressionOption {
88                         get; private set;
89                 }
90
91                 public string ContentType {
92                         get {
93                                 if (contentType == null && (contentType = GetContentTypeCore()) == null)
94                                         throw new NotSupportedException ("If contentType is not supplied in the constructor, GetContentTypeCore must be overridden");
95                                 return contentType;
96                         }
97                         private set {
98                                 contentType = value;
99                         }
100                 }
101
102                 public Package Package {
103                         get; internal set;
104                 }
105
106                 public Uri Uri {
107                         get; private set;
108                 }
109
110                 private void CheckIsRelationship ()
111                 {
112                         if (IsRelationship)
113                                 throw new InvalidOperationException ("A relationship cannot have relationships to other parts"); 
114                 }
115
116                 public PackageRelationship CreateRelationship (Uri targetUri, TargetMode targetMode, string relationshipType)
117                 {
118                         return CreateRelationship (targetUri, targetMode, relationshipType, null);
119                 }
120
121                 public PackageRelationship CreateRelationship (Uri targetUri, TargetMode targetMode, string relationshipType, string id)
122                 {
123                         return CreateRelationship (targetUri, targetMode, relationshipType, id, false);
124                 }
125
126                 private PackageRelationship CreateRelationship (Uri targetUri, TargetMode targetMode, string relationshipType, string id, bool loading)
127                 {
128                         Package.CheckIsReadOnly ();
129                         Check.TargetUri (targetUri);
130                         Check.RelationshipTypeIsValid (relationshipType);
131                         Check.IdIsValid (id);
132
133                         if (id == null)
134                                 id = NextId ();
135
136                         if (Relationships.ContainsKey (id))
137                                 throw new XmlException ("A relationship with this ID already exists");
138                         
139                         PackageRelationship r = new PackageRelationship (id, Package, relationshipType, Uri, targetMode, targetUri);
140                         Relationships.Add (r.Id, r);
141
142                         if (!loading)
143                                 WriteRelationships ();
144                         return r;
145                 }
146
147                 public void DeleteRelationship (string id)
148                 {
149                         Package.CheckIsReadOnly ();
150                         CheckIsRelationship ();
151                         Relationships.Remove (id);
152                         WriteRelationships ();
153                 }
154
155                 void LoadRelationships (Dictionary<string, PackageRelationship> relationships, Stream stream)
156                 {
157                         XmlDocument doc = new XmlDocument ();
158                         doc.Load (stream);
159                         XmlNamespaceManager manager = new XmlNamespaceManager (doc.NameTable);
160                         manager.AddNamespace ("rel", Package.RelationshipNamespace);
161
162                         foreach (XmlNode node in doc.SelectNodes ("/rel:Relationships/*", manager))
163                         {
164                                 TargetMode mode = TargetMode.Internal;
165                                 if (node.Attributes["TargetMode"] != null)
166                                         mode = (TargetMode) Enum.Parse (typeof(TargetMode), node.Attributes ["TargetMode"].Value);
167                                 
168                                 CreateRelationship (new Uri (node.Attributes["Target"].Value.ToString(), UriKind.RelativeOrAbsolute),
169                                                     mode,
170                                                     node.Attributes["Type"].Value.ToString (),
171                                                     node.Attributes["Id"].Value.ToString (),
172                                                     true);
173                         }
174                 }
175
176                 public bool RelationshipExists (string id)
177                 {
178                         CheckIsRelationship ();
179                         return Relationships.ContainsKey (id);
180                 }
181
182                 public PackageRelationship GetRelationship (string id)
183                 {
184                         CheckIsRelationship ();
185                         return Relationships [id];
186                 }
187
188                 public PackageRelationshipCollection GetRelationships ()
189                 {
190                         CheckIsRelationship ();
191                         relationshipsCollection.Relationships.Clear ();
192                         relationshipsCollection.Relationships.AddRange (Relationships.Values);
193                         return relationshipsCollection;
194                 }
195
196                 public PackageRelationshipCollection GetRelationshipsByType (string relationshipType)
197                 {
198                         CheckIsRelationship ();
199                         PackageRelationshipCollection collection = new PackageRelationshipCollection ();
200                         foreach (PackageRelationship r in Relationships.Values)
201                                 if (r.RelationshipType == relationshipType)
202                                         collection.Relationships.Add (r);
203                         
204                         return collection;
205                 }
206
207                 public Stream GetStream ()
208                 {
209                         return GetStream (Package.FileOpenAccess == FileAccess.Read && !IsRelationship ? FileMode.Open : FileMode.OpenOrCreate);
210                 }
211
212                 public Stream GetStream (FileMode mode)
213                 {
214                         return GetStream (mode, IsRelationship ? FileAccess.ReadWrite : Package.FileOpenAccess);
215                 }
216
217                 public Stream GetStream (FileMode mode, FileAccess access)
218                 {
219                         bool notAllowed = mode == FileMode.Append || mode == FileMode.CreateNew || mode == FileMode.Truncate;
220                         if (access != FileAccess.Read && notAllowed)
221                                 throw new ArgumentException (string.Format (string.Format ("FileMode '{0}' not supported", mode)));
222
223                         if (access == FileAccess.Read && (notAllowed || mode == FileMode.Create))
224                                 throw new IOException (string.Format ("FileMode '{0}' not allowed on a readonly stream", mode));
225                         
226                         return GetStreamCore (mode, access);
227                 }
228
229                 protected abstract Stream GetStreamCore (FileMode mode, FileAccess access);
230
231                 protected virtual string GetContentTypeCore ()
232                 {
233                         return null;
234                 }
235
236                 private string NextId ()
237                 {
238                         while (true)
239                         {
240                                 string s = "Re" + relationshipId.ToString ();
241                                 if (!RelationshipExists (s))
242                                         return s;
243                                 relationshipId ++;
244                         }
245                 }
246
247                 void WriteRelationships ()
248                 {
249                         bool exists = Package.PartExists (RelationshipsPartUri);
250                         if (exists && Relationships.Count == 0)
251                         {
252                                 Package.DeletePart (RelationshipsPartUri);
253                                 return;
254                         }
255                         
256                         if (!exists)
257                         {
258                                 PackagePart part = Package.CreatePart (RelationshipsPartUri, Package.RelationshipContentType);
259                                 part.IsRelationship = true;
260                         }
261                         using (Stream s = Package.GetPart (RelationshipsPartUri).GetStream ())
262                                 Package.WriteRelationships (Relationships, s);
263                 }
264         }
265 }