4
// Copyright (C) 2008 D Bera<dbera.web@gmail.com>
6
// Permission is hereby granted, free of charge, to any person obtaining a
7
// copy of this software and associated documentation files (the "Software"),
8
// to deal in the Software without restriction, including without limitation
9
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
// and/or sell copies of the Software, and to permit persons to whom the
11
// Software is furnished to do so, subject to the following conditions:
13
// The above copyright notice and this permission notice shall be included in
14
// all copies or substantial portions of the Software.
16
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
// DEALINGS IN THE SOFTWARE.
28
using System.Text.RegularExpressions;
33
using ICSharpCode.SharpZipLib.GZip;
34
using ICSharpCode.SharpZipLib.BZip2;
35
using Decoder = SevenZip.Compression.LZMA.Decoder;
37
namespace Beagle.Filters {
39
public class FilterInfo : Beagle.Daemon.Filter {
43
SetFileType ("documentation");
46
protected override void RegisterSupportedTypes ()
49
AddSupportedFlavor (new FilterFlavor ("file:///usr/share/info/*", ".lzma", null, 1));
50
AddSupportedFlavor (new FilterFlavor ("file:///usr/share/info/*", ".gz", null, 1));
51
AddSupportedFlavor (new FilterFlavor ("file:///usr/share/info/*", ".bz2", null, 1));
52
AddSupportedFlavor (new FilterFlavor ("file:///usr/share/info/*", ".info", null, 1));
55
const char c = ''; // Info node separator
56
private bool skipping = false; // use this to skip certain nodes
57
static readonly char[] node_line_sep = new char[] {'*', ':', '.', ','};
59
private TextReader reader;
61
protected override void DoOpen (FileInfo info)
63
if (Extension == ".gz" || Extension == ".bz2" || Extension == ".lzma")
64
GetCompressedInfoReader ();
66
reader = base.TextReader;
69
override protected void DoPullProperties ()
71
// start reading lines till the first node is hit
73
while ((line = reader.ReadLine ()) != null) {
79
skipping = ReportNewNode ();
86
string[] words = line.Split (node_line_sep, StringSplitOptions.RemoveEmptyEntries);
87
AddProperty (Beagle.Property.New ("dc:title", words [0].Trim ()));
98
override protected void DoPull ()
102
line = reader.ReadLine ();
108
if (line.Length == 0)
111
if (skipping && line [0] != c)
115
if (! skipping && ! line.StartsWith ("*"))
120
skipping = ReportNewNode ();
123
// Returns true if the node should be skipped
124
private bool ReportNewNode ()
126
// Starting a new node
127
// Read the next line
128
string line = reader.ReadLine ();
134
if (line.StartsWith ("Indirect:") ||
135
line.StartsWith ("Tag Table:") ||
136
line.Contains ("Node: Index") ||
137
line.Contains ("Node: Top")) {
144
private void GetCompressedInfoReader ()
146
StreamReader compressed_reader = null;
149
Stream stream = null;
150
if (Extension == ".gz")
151
stream = new GZipInputStream (Stream);
152
else if (Extension == ".bz2")
153
stream = new BZip2InputStream (Stream);
154
else if (Extension == ".lzma")
155
stream = GetLzmaStream (Stream);
157
compressed_reader = new StreamReader (stream);
158
} catch (Exception e) {
159
Log.Error (e, "Error in opening compressed man page");
160
if (compressed_reader != null)
161
compressed_reader.Close ();
166
reader = compressed_reader;
169
protected override void DoClose ()
171
if (Extension == ".gz" || Extension == ".bz2" || Extension == ".lzma")
176
private Stream GetLzmaStream (Stream in_stream)
179
byte[] properties = new byte [5];
180
if (in_stream.Read (properties, 0, 5) != 5)
181
throw new Exception ("input .lzma is too short");
183
Decoder decoder = new Decoder ();
184
decoder.SetDecoderProperties (properties);
187
for (int i = 0; i < 8; i++)
189
int v = in_stream.ReadByte ();
191
throw new Exception ("LZMA: Can't Read 1");
192
out_size |= ((long)(byte)v) << (8 * i);
194
long compressed_size = in_stream.Length - in_stream.Position;
196
// FIXME: Man pages are small enough to use a MemoryStream to store the
197
// entire uncompressed file.
198
// Still, a proper stream based approach would be good. Unfortunately,
199
// LZMA does not provide a streaming interface. Current hacks involve
200
// a separate synchronized thread.
201
MemoryStream out_stream = new MemoryStream ((int) out_size); // outsize is long but this constructor is resizable
202
decoder.Code (in_stream, out_stream, compressed_size, out_size, null);
203
//Log.Debug ("Decoded {0} bytes to {1} bytes", compressed_size, out_size);
204
out_stream.Position = 0;