Add a new archived file tile to beagle-search. Still needs a little love.
[beagle.git] / Filters / FilterArchive.cs
blob6e0b005516da9c3f708aed7962fe38709f19e13c
1 //
2 // FilterArchive.cs
3 //
4 // Copyright (C) 2004-2006 Novell, Inc.
5 //
6 //
7 //
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.
27 using System;
28 using System.Collections;
29 using System.IO;
31 using ICSharpCode.SharpZipLib;
32 using ICSharpCode.SharpZipLib.Zip;
33 using ICSharpCode.SharpZipLib.GZip;
34 using ICSharpCode.SharpZipLib.BZip2;
35 using ICSharpCode.SharpZipLib.Tar;
37 using Beagle;
38 using Beagle.Daemon;
39 using Beagle.Util;
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;
66 switch (MimeType) {
67 case "application/zip":
68 archive_stream = new ZipInputStream (Stream);
69 get_next_entry = GetNextEntryZip;
70 break;
72 case "application/x-bzip-compressed-tar":
73 archive_stream = new TarInputStream (new BZip2InputStream (Stream));
74 get_next_entry = GetNextEntryTar;
75 break;
77 case "application/x-compressed-tar":
78 case "application/x-tgz":
79 archive_stream = new TarInputStream (new GZipInputStream (Stream));
80 get_next_entry = GetNextEntryTar;
81 break;
83 case "application/x-tar":
84 archive_stream = new TarInputStream (Stream);
85 get_next_entry = GetNextEntryTar;
86 break;
88 case "application/x-gzip":
89 archive_stream = new GZipInputStream (Stream);
90 get_next_entry = GetNextEntrySingle;
91 break;
93 case "application/x-bzip":
94 archive_stream = new BZip2InputStream (Stream);
95 get_next_entry = GetNextEntrySingle;
96 break;
98 default:
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 {
140 public string Name;
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)
150 if (stream == null)
151 return null;
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];
161 int read;
163 do {
164 read = stream.Read (buffer, 0, buffer.Length);
165 if (read > 0)
166 buffered_stream.Write (buffer, 0, read);
167 } while (read > 0);
169 buffered_stream.Close ();
171 File.SetLastWriteTimeUtc (filename, mtime);
173 Mono.Unix.Native.Syscall.chmod (filename, (Mono.Unix.Native.FilePermissions) 256); // 256 is 0400
175 return filename;
178 private ArchiveEntry GetNextEntryZip ()
180 ZipInputStream zip_stream = (ZipInputStream) archive_stream;
181 ZipEntry zip_entry;
183 do {
184 zip_entry = zip_stream.GetNextEntry ();
185 } while (zip_entry != null && zip_entry.IsDirectory);
187 // End of the entries.
188 if (zip_entry == null)
189 return 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);
199 return entry;
202 private ArchiveEntry GetNextEntryTar ()
204 TarInputStream tar_stream = (TarInputStream) archive_stream;
205 TarEntry tar_entry;
207 do {
208 tar_entry = tar_stream.GetNextEntry ();
209 } while (tar_entry != null && tar_entry.IsDirectory);
211 // End of the entries;
212 if (tar_entry == null)
213 return 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);
222 return entry;
225 private bool handled_single = false;
227 private ArchiveEntry GetNextEntrySingle ()
229 if (handled_single)
230 return null;
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;
241 return entry;