Add FilterArchive from bugzilla with some minor modifications. Archive filter needs...
[beagle.git] / Filters / FilterArchive.cs
bloba0ce50033d26267001c288b39e95cc0df9bfd374
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, IDisposable {
45 Archive archive = null;
46 ArchiveHandler tarHandler = null;
48 public FilterArchive ()
50 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/zip"));
51 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-bzip-compressed-tar"));
52 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-compressed-tar"));
53 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-tar"));
54 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-tgz"));
55 //AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-gzip"));
56 //AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-bzip"));
59 protected override void DoOpen (FileInfo info)
61 archive = new Archive (info.FullName, MimeType);
64 protected override void DoPullProperties ()
66 // FIXME: Fetch the archive properties.
69 protected override void DoPullSetup ()
71 this.tarHandler = new ArchiveHandler (this);
72 this.tarHandler.OnEachEntry (archive);
74 AddChildIndexables (this.tarHandler.ChildIndexables);
77 protected override void DoClose ()
79 Dispose ();
82 public void Dispose ()
84 if (this.archive != null)
85 archive.Close ();
88 private class ArchiveEntry {
89 private string name;
90 private long size;
91 private string mimetype;
92 private bool is_directory;
93 private DateTime modified;
94 private string uri;
95 private string comment;
96 private string temp_file_name;
98 public ArchiveEntry ()
100 name = null;
101 size = 0;
102 mimetype = null;
103 is_directory = false;
104 modified = DateTimeUtil.UnixToDateTimeUtc (0);
105 comment = null;
106 temp_file_name = null;
109 public string Name {
110 get {
111 return name;
114 set {
115 name = value;
119 public string MimeType {
120 get {
121 return mimetype;
124 set {
125 mimetype = value;
129 public System.DateTime Modified {
130 get {
131 return modified;
134 set {
135 modified = value;
139 public long Size {
140 get {
141 return size;
144 set {
145 size = value;
149 public bool IsDirectory {
150 get {
151 return is_directory;
154 set {
155 is_directory = value;
159 public string Uri {
160 get {
161 return uri;
164 set {
165 uri = value;
169 public string Comment {
170 get {
171 return comment;
174 set {
175 comment = value;
179 public string TempFileName {
180 get {
181 return temp_file_name;
184 set {
185 temp_file_name = value;
191 private class Archive : Stream
193 Stream base_stream = null;
194 string uri = null;
195 string name = null;
196 string method = null;
198 delegate ArchiveEntry GetNextEntryType ();
199 GetNextEntryType getNextEntry;
200 bool first = true;
202 public Archive (string filename, string mimeType) {
203 this.uri = UriFu.PathToFileUriString (filename);
204 name = filename;
205 base_stream = new FileStream (filename,
206 FileMode.Open,
207 FileAccess.Read);
208 Init (base_stream, mimeType);
212 private void Init (Stream stream, string mimeType) {
214 switch (mimeType) {
215 case "application/zip":
216 base_stream = new ZipInputStream (base_stream);
217 getNextEntry = new GetNextEntryType (GetNextEntryZip);
218 method = "zip:";
219 break;
220 case "application/x-bzip-compressed-tar":
221 base_stream = new BZip2InputStream (base_stream);
222 base_stream = new TarInputStream (base_stream);
223 getNextEntry = new GetNextEntryType (GetNextEntryTar);
224 method = "bzip2tar:";
225 break;
226 case "application/x-compressed-tar":
227 case "application/x-tgz":
228 base_stream = new GZipInputStream (base_stream);
229 base_stream = new TarInputStream (base_stream);
230 getNextEntry = new GetNextEntryType (GetNextEntryTar);
231 method = "gziptar:";
232 break;
233 case "application/x-tar":
234 base_stream = new TarInputStream (base_stream);
235 getNextEntry = new GetNextEntryType (GetNextEntryTar);
236 method = "tar:";
237 break;
238 case "application/x-gzip":
239 base_stream = new GZipInputStream (base_stream);
240 getNextEntry = new GetNextEntryType (GetNextEntrySingle);
241 method = "gzip:";
242 break;
243 case "application/x-bzip":
244 base_stream = new BZip2InputStream (base_stream);
245 getNextEntry = new GetNextEntryType (GetNextEntrySingle);
246 method = "bzip:";
247 break;
248 default:
249 throw new ArgumentException ("Invalid or unsupported mime type.");
254 public string GetNextEntrySingleAsUri () {
255 if (first) {
256 first = false;
257 return uri + method;
258 } else
259 return null;
263 /* Returns stream of the next entry */
264 public ArchiveEntry GetNextEntry ()
266 return getNextEntry ();
269 private String GetEntryFile (string entry_name)
271 string temp_file = null;
272 //temp_file = Path.Combine (Path.GetTempPath (), entry_name);
273 temp_file = Path.GetTempFileName ();
274 File.Delete (temp_file);
275 temp_file = temp_file + Path.GetExtension (entry_name);
276 Console.WriteLine ("GetEntryFile: temp_file = {0}", temp_file);
277 FileStream filestream = File.OpenWrite (temp_file);
279 BufferedStream buffered_stream = new BufferedStream (filestream);
280 BinaryWriter writer = new BinaryWriter (buffered_stream);
282 const int BUFFER_SIZE = 8192;
283 byte[] data = new byte [BUFFER_SIZE];
285 int read;
286 do {
287 read = base_stream.Read (data, 0, BUFFER_SIZE);
288 if (read > 0)
289 writer.Write (data, 0, read);
290 } while (read > 0);
292 writer.Close ();
294 File.SetLastWriteTime (temp_file, File.GetLastWriteTime (this.name));
295 return temp_file;
298 public ArchiveEntry GetNextEntryZip () {
299 ArchiveEntry a_entry = null;
301 ZipInputStream inputStream = base_stream as ZipInputStream;
302 ZipEntry entry = inputStream.GetNextEntry();
303 if (entry != null && !entry.IsDirectory) {
304 a_entry = new ArchiveEntry ();
305 a_entry.Uri = /* DB uri + method + */entry.Name;
306 a_entry.Size = entry.Size;
307 a_entry.Modified = entry.DateTime;
308 a_entry.IsDirectory = entry.IsDirectory;
309 a_entry.Name = entry.Name;
310 a_entry.TempFileName = GetEntryFile (entry.Name);
311 a_entry.MimeType = Beagle.Util.XdgMime.GetMimeType (a_entry.TempFileName);
312 a_entry.Comment = entry.Comment;
314 return a_entry;
317 public ArchiveEntry GetNextEntrySingle () {
318 if (first) {
319 first = false;
320 return null;
321 } else
322 return null;
325 public ArchiveEntry GetNextEntryTar () {
326 ArchiveEntry a_entry = null;
327 TarInputStream inputStream = base_stream as TarInputStream;
328 TarEntry entry = inputStream.GetNextEntry();
329 if (entry != null && !entry.IsDirectory) {
330 a_entry = new ArchiveEntry ();
331 a_entry.Uri = /* DB uri + method + */entry.Name;
332 a_entry.Size = entry.Size;
333 a_entry.Modified = entry.ModTime;
334 a_entry.IsDirectory = entry.IsDirectory;
335 a_entry.Name = entry.Name;
336 a_entry.TempFileName = GetEntryFile (entry.Name);
337 a_entry.MimeType = Beagle.Util.XdgMime.GetMimeType (a_entry.TempFileName);
339 return a_entry;
342 public override int Read (byte[] buffer, int offset, int length) {
343 return base_stream.Read (buffer, offset, length);
346 public override IAsyncResult BeginRead (byte[] buffer, int offset, int length,
347 AsyncCallback cback, object state)
349 return base_stream.BeginRead (buffer, offset, length, cback, state);
352 public override int EndRead(IAsyncResult async_result) {
353 return base_stream.EndRead (async_result);
356 public override void Write (byte[] buffer, int offset, int length) {
357 throw new NotSupportedException ();
359 public override void Flush () {
360 throw new NotSupportedException ();
362 public override long Seek (long offset, SeekOrigin origin) {
363 throw new NotSupportedException ();
365 public override void SetLength (long value) {
366 throw new System.NotSupportedException();
368 public override bool CanRead {
369 get {
370 return base_stream.CanRead;
373 public override bool CanSeek {
374 get {
375 return false;
378 public override bool CanWrite {
379 get {
380 return false;
383 public override long Length {
384 get {
385 throw new System.NotSupportedException();
388 public override long Position {
389 get {
390 throw new System.NotSupportedException();
392 set {
393 throw new System.NotSupportedException();
399 private class ArchiveHandler {
400 private Beagle.Daemon.Filter filter;
401 private ArrayList child_indexables = new ArrayList ();
402 private int count = 0; // entries handled so far
404 public ArchiveHandler (Beagle.Daemon.Filter filter)
406 this.filter = filter;
409 public void OnEachEntry (Archive archive)
411 ArchiveEntry a_entry = null;
413 //Log.Debug ("{0}.GetNextentry", archive.filename);
414 while ((a_entry = archive.GetNextEntry ()) != null) {
415 // FIXME: For nested archives, create uid:foo#bar
416 // instead of uid:foo#xxx#bar (avoid duplicates ?)
417 Indexable child = new Indexable (new Uri (filter.Uri.ToString () + "#" + a_entry.Uri, true));
419 child.CacheContent = false;
420 child.MimeType = a_entry.MimeType;
421 child.ContentUri = UriFu.PathToFileUri (a_entry.TempFileName);
422 child.DeleteContent = true;
424 //Log.Debug ("Creating child with uri={0}, content-uri={1}",
425 // a_entry.Uri,
426 // child.ContentUri);
427 //Console.WriteLine ("Name: {0}, MimeType: {1}", sub_uri, child.MimeType);
429 if (a_entry.Comment != null)
430 child.AddProperty (Property.New ("fixme:comment", a_entry.Comment));
431 child.AddProperty (Property.New ("fixme:name", a_entry.Name));
432 child.AddProperty (Property.NewKeyword ("fixme:size", a_entry.Size));
433 child.AddProperty (Property.New ("fixme:relativeuri", a_entry.Uri));
434 foreach (Property prop in Property.StandardFileProperties (Path.GetFileName (a_entry.Name), false))
435 child.AddProperty (prop);
437 //child.SetBinaryStream (File.OpenRead (a_entry.Name));
439 this.child_indexables.Add (child);
440 this.count++;
444 public ICollection ChildIndexables {
445 get { return this.child_indexables; }