4 // Copyright (C) 2004-2006 Novell, Inc.
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
28 using System
.Collections
;
31 using ICSharpCode
.SharpZipLib
;
32 using ICSharpCode
.SharpZipLib
.Zip
;
33 using ICSharpCode
.SharpZipLib
.GZip
;
34 using ICSharpCode
.SharpZipLib
.BZip2
;
35 using ICSharpCode
.SharpZipLib
.Tar
;
41 namespace Beagle
.Filters
{
43 public class FilterArchive
: Beagle
.Daemon
.Filter
{
45 internal delegate ArchiveEntry
GetNextEntry ();
47 private FileInfo file_info
;
48 private Stream archive_stream
;
49 private GetNextEntry get_next_entry
;
51 public FilterArchive ()
53 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/zip"));
54 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-bzip-compressed-tar"));
55 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-compressed-tar"));
56 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-tar"));
57 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-tgz"));
58 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-gzip"));
59 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-bzip"));
62 protected override void DoOpen (FileInfo file_info
)
64 this.file_info
= file_info
;
67 case "application/zip":
68 archive_stream
= new ZipInputStream (Stream
);
69 get_next_entry
= GetNextEntryZip
;
72 case "application/x-bzip-compressed-tar":
73 archive_stream
= new TarInputStream (new BZip2InputStream (Stream
));
74 get_next_entry
= GetNextEntryTar
;
77 case "application/x-compressed-tar":
78 case "application/x-tgz":
79 archive_stream
= new TarInputStream (new GZipInputStream (Stream
));
80 get_next_entry
= GetNextEntryTar
;
83 case "application/x-tar":
84 archive_stream
= new TarInputStream (Stream
);
85 get_next_entry
= GetNextEntryTar
;
88 case "application/x-gzip":
89 archive_stream
= new GZipInputStream (Stream
);
90 get_next_entry
= GetNextEntrySingle
;
93 case "application/x-bzip":
94 archive_stream
= new BZip2InputStream (Stream
);
95 get_next_entry
= GetNextEntrySingle
;
99 throw new ArgumentException ("Invalid or unsupported mime type.");
104 protected override void DoPullProperties ()
106 // FIXME: Fetch the archive properties.
109 protected override void DoPullSetup ()
111 ArchiveEntry a_entry
;
113 while ((a_entry
= this.get_next_entry ()) != null) {
114 // FIXME: For nested archives, create uid:foo#bar
115 // instead of uid:foo#xxx#bar (avoid duplicates ?)
116 Indexable child
= new Indexable (new Uri (Uri
.ToString () + "#" + a_entry
.Name
, true));
118 child
.CacheContent
= false;
119 child
.MimeType
= a_entry
.MimeType
;
121 child
.DisplayUri
= new Uri (DisplayUri
.ToString () + "#" + a_entry
.Name
, true);
122 child
.ContentUri
= UriFu
.PathToFileUri (a_entry
.TempFile
);
123 child
.DeleteContent
= true;
125 child
.AddProperty (Property
.NewBool ("fixme:inside_archive", true));
127 child
.AddProperty (Property
.NewKeyword ("fixme:relativeuri", a_entry
.Name
));
129 if (a_entry
.Comment
!= null)
130 child
.AddProperty (Property
.New ("fixme:comment", a_entry
.Comment
));
132 foreach (Property prop
in Property
.StandardFileProperties (Path
.GetFileName (a_entry
.Name
), false))
133 child
.AddProperty (prop
);
135 AddChildIndexable (child
);
139 internal class ArchiveEntry
{
141 public string MimeType
;
142 public DateTime Modified
;
143 public string Comment
;
145 public string TempFile
;
148 private static string StoreStreamInTempFile (Stream stream
, DateTime mtime
)
153 string filename
= Path
.GetTempFileName ();
154 FileStream file_stream
= File
.OpenWrite (filename
);
156 Mono
.Unix
.Native
.Syscall
.chmod (filename
, (Mono
.Unix
.Native
.FilePermissions
) 384); // 384 is 0600
158 BufferedStream buffered_stream
= new BufferedStream (file_stream
);
160 byte [] buffer
= new byte [8192];
164 read
= stream
.Read (buffer
, 0, buffer
.Length
);
166 buffered_stream
.Write (buffer
, 0, read
);
169 buffered_stream
.Close ();
171 File
.SetLastWriteTimeUtc (filename
, mtime
);
173 Mono
.Unix
.Native
.Syscall
.chmod (filename
, (Mono
.Unix
.Native
.FilePermissions
) 256); // 256 is 0400
178 private ArchiveEntry
GetNextEntryZip ()
180 ZipInputStream zip_stream
= (ZipInputStream
) archive_stream
;
184 zip_entry
= zip_stream
.GetNextEntry ();
185 } while (zip_entry
!= null && zip_entry
.IsDirectory
);
187 // End of the entries.
188 if (zip_entry
== null)
191 ArchiveEntry entry
= new ArchiveEntry ();
192 entry
.Name
= zip_entry
.Name
;
193 entry
.Modified
= zip_entry
.DateTime
; // FIXME: Not sure zip_entry.DateTime is UTC.
194 entry
.Comment
= zip_entry
.Comment
;
196 entry
.TempFile
= StoreStreamInTempFile (archive_stream
, entry
.Modified
);
197 entry
.MimeType
= XdgMime
.GetMimeType (entry
.TempFile
);
202 private ArchiveEntry
GetNextEntryTar ()
204 TarInputStream tar_stream
= (TarInputStream
) archive_stream
;
208 tar_entry
= tar_stream
.GetNextEntry ();
209 } while (tar_entry
!= null && tar_entry
.IsDirectory
);
211 // End of the entries;
212 if (tar_entry
== null)
215 ArchiveEntry entry
= new ArchiveEntry ();
216 entry
.Name
= tar_entry
.Name
;
217 entry
.Modified
= tar_entry
.ModTime
;
219 entry
.TempFile
= StoreStreamInTempFile (archive_stream
, entry
.Modified
);
220 entry
.MimeType
= XdgMime
.GetMimeType (entry
.TempFile
);
225 private bool handled_single
= false;
227 private ArchiveEntry
GetNextEntrySingle ()
232 ArchiveEntry entry
= new ArchiveEntry ();
233 entry
.Name
= Path
.GetFileNameWithoutExtension (this.file_info
.Name
);
234 entry
.Modified
= this.file_info
.LastWriteTimeUtc
;
236 entry
.TempFile
= StoreStreamInTempFile (archive_stream
, entry
.Modified
);
237 entry
.MimeType
= XdgMime
.GetMimeType (entry
.TempFile
);
239 handled_single
= true;