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
, 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 ()
82 public void Dispose ()
84 if (this.archive
!= null)
88 private class ArchiveEntry
{
91 private string mimetype
;
92 private bool is_directory
;
93 private DateTime modified
;
95 private string comment
;
96 private string temp_file_name
;
98 public ArchiveEntry ()
103 is_directory
= false;
104 modified
= DateTimeUtil
.UnixToDateTimeUtc (0);
106 temp_file_name
= null;
119 public string MimeType
{
129 public System
.DateTime Modified
{
149 public bool IsDirectory
{
155 is_directory
= value;
169 public string Comment
{
179 public string TempFileName
{
181 return temp_file_name
;
185 temp_file_name
= value;
191 private class Archive
: Stream
193 Stream base_stream
= null;
196 string method
= null;
198 delegate ArchiveEntry
GetNextEntryType ();
199 GetNextEntryType getNextEntry
;
202 public Archive (string filename
, string mimeType
) {
203 this.uri
= UriFu
.PathToFileUriString (filename
);
205 base_stream
= new FileStream (filename
,
208 Init (base_stream
, mimeType
);
212 private void Init (Stream stream
, string mimeType
) {
215 case "application/zip":
216 base_stream
= new ZipInputStream (base_stream
);
217 getNextEntry
= new GetNextEntryType (GetNextEntryZip
);
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:";
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
);
233 case "application/x-tar":
234 base_stream
= new TarInputStream (base_stream
);
235 getNextEntry
= new GetNextEntryType (GetNextEntryTar
);
238 case "application/x-gzip":
239 base_stream
= new GZipInputStream (base_stream
);
240 getNextEntry
= new GetNextEntryType (GetNextEntrySingle
);
243 case "application/x-bzip":
244 base_stream
= new BZip2InputStream (base_stream
);
245 getNextEntry
= new GetNextEntryType (GetNextEntrySingle
);
249 throw new ArgumentException ("Invalid or unsupported mime type.");
254 public string GetNextEntrySingleAsUri () {
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
];
287 read
= base_stream
.Read (data
, 0, BUFFER_SIZE
);
289 writer
.Write (data
, 0, read
);
294 File
.SetLastWriteTime (temp_file
, File
.GetLastWriteTime (this.name
));
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
;
317 public ArchiveEntry
GetNextEntrySingle () {
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
);
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
{
370 return base_stream
.CanRead
;
373 public override bool CanSeek
{
378 public override bool CanWrite
{
383 public override long Length
{
385 throw new System
.NotSupportedException();
388 public override long Position
{
390 throw new System
.NotSupportedException();
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}",
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
);
444 public ICollection ChildIndexables
{
445 get { return this.child_indexables; }