/* * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using BufferedIndexInput = Lucene.Net.Store.BufferedIndexInput; using Directory = Lucene.Net.Store.Directory; using IndexInput = Lucene.Net.Store.IndexInput; using IndexOutput = Lucene.Net.Store.IndexOutput; using Lock = Lucene.Net.Store.Lock; namespace Lucene.Net.Index { /// Class for accessing a compound stream. /// This class implements a directory, but is limited to only read operations. /// Directory methods that would normally modify data throw an exception. /// /// /// Dmitry Serebrennikov /// /// $Id: CompoundFileReader.cs,v 1.3 2005/10/06 19:29:55 dsd Exp $ /// public class CompoundFileReader : Directory { private sealed class FileEntry { internal long offset; internal long length; } // Base info private Directory directory; private System.String fileName; private IndexInput stream; private System.Collections.Hashtable entries = new System.Collections.Hashtable(); public CompoundFileReader(Directory dir, System.String name) { directory = dir; fileName = name; bool success = false; try { stream = dir.OpenInput(name); // read the directory and init files int count = stream.ReadVInt(); FileEntry entry = null; for (int i = 0; i < count; i++) { long offset = stream.ReadLong(); System.String id = stream.ReadString(); if (entry != null) { // set length of the previous entry entry.length = offset - entry.offset; } entry = new FileEntry(); entry.offset = offset; entries[id] = entry; } // set the length of the final entry if (entry != null) { entry.length = stream.Length() - entry.offset; } success = true; } finally { if (!success && (stream != null)) { try { stream.Close(); } catch (System.IO.IOException e) { } } } } public virtual Directory GetDirectory() { return directory; } public virtual System.String GetName() { return fileName; } public override void Close() { lock (this) { if (stream == null) throw new System.IO.IOException("Already closed"); entries.Clear(); stream.Close(); stream = null; } } public override IndexInput OpenInput(System.String id) { lock (this) { if (stream == null) throw new System.IO.IOException("Stream closed"); FileEntry entry = (FileEntry) entries[id]; if (entry == null) throw new System.IO.IOException("No sub-file with id " + id + " found"); return new CSIndexInput(stream, entry.offset, entry.length); } } /// Returns an array of strings, one for each file in the directory. public override System.String[] List() { System.String[] res = new System.String[entries.Count]; entries.Keys.CopyTo(res, 0); return res; } /// Returns true iff a file with the given name exists. public override bool FileExists(System.String name) { return entries.ContainsKey(name); } /// Returns the time the named file was last modified. public override long FileModified(System.String name) { return directory.FileModified(fileName); } /// Set the modified time of an existing file to now. public override void TouchFile(System.String name) { directory.TouchFile(fileName); } /// Not implemented /// UnsupportedOperationException public override void DeleteFile(System.String name) { throw new System.NotSupportedException(); } /// Not implemented /// UnsupportedOperationException public override void RenameFile(System.String from, System.String to) { throw new System.NotSupportedException(); } /// Returns the length of a file in the directory. /// IOException if the file does not exist public override long FileLength(System.String name) { FileEntry e = (FileEntry) entries[name]; if (e == null) throw new System.IO.IOException("File " + name + " does not exist"); return e.length; } /// Not implemented /// UnsupportedOperationException public override IndexOutput CreateOutput(System.String name) { throw new System.NotSupportedException(); } /// Not implemented /// UnsupportedOperationException public override Lock MakeLock(System.String name) { throw new System.NotSupportedException(); } /// Implementation of an IndexInput that reads from a portion of the /// compound file. The visibility is left as "package" *only* because /// this helps with testing since JUnit test cases in a different class /// can then access package fields of this class. /// public /*internal*/ sealed class CSIndexInput : BufferedIndexInput { public /*internal*/ IndexInput base_Renamed; internal long fileOffset; internal long length; internal CSIndexInput(IndexInput base_Renamed, long fileOffset, long length) { this.base_Renamed = base_Renamed; this.fileOffset = fileOffset; this.length = length; } /// Expert: implements buffer refill. Reads bytes from the current /// position in the input. /// /// the array to read bytes into /// /// the offset in the array to start storing bytes /// /// the number of bytes to read /// public override void ReadInternal(byte[] b, int offset, int len) { lock (base_Renamed) { long start = GetFilePointer(); if (start + len > length) throw new System.IO.IOException("read past EOF"); base_Renamed.Seek(fileOffset + start); base_Renamed.ReadBytes(b, offset, len); } } /// Expert: implements seek. Sets current position in this file, where /// the next {@link #ReadInternal(byte[],int,int)} will occur. /// /// /// public override void SeekInternal(long pos) { } /// Closes the stream to further operations. public override void Close() { } public override long Length() { return length; } } } }