IFilter ErrorCode FILTER_E_ACCESS when reading .rtf (Rick Text format) from byte array
문제
I'm using this http://www.codeproject.com/Articles/31944/Implementing-a-TextReader-to-extract-various-files and it's mostly working.
I wrote this test to check if the Filter would read as expected from a byte array.
private const string ExpectedText = "This is a test!";
[Test]
public void FilterReader_RtfBytes_TextMatch()
{
var bytes = File.ReadAllBytes(@"Test Documents\DocTest.rtf");
var reader = new FilterReader(bytes, ".rtf");
reader.Init();
var actualText = reader.ReadToEnd();
StringAssert.Contains(ExpectedText, actualText);
}
The test fails with ErrorCode : FILTER_E_ACCESS, it works fine when I give it the filename.
new FilterReader(@"Test Documents\DocTest.rtf", ".rtf"); <-- works
I'm puzzled as to why that is. I looked through the code and it seems it's the rtf filter dll that returns the error. Which is even more puzzling.
It works fine for other file types, like; .doc, .docx, .pdf
해결책
under the hood the using of concrete way of work with iFilter is defined by constructor: when you use constructor FilterReader(byte[] bytes, string extension)
is used IPersistStream for content loading from memory, when FilterReader(string path, string extension)
- IPersistFile for loading from file.
why rtf-ifilter returns error when used with IPersistStream i'm afraid we will not able to know because source code isn't opened
in my case i encapsulate filter's specific in constructor and refactor code next way:
- remove all constructors
- remove
public void Init()
-method implement one custom constructor
public FilterReader(string fileName, string extension, uint blockSize = 0x2000)
:#region Contracts Contract.Requires(!string.IsNullOrEmpty(fileName)); Contract.Requires(!string.IsNullOrEmpty(extension)); Contract.Requires(blockSize > 1); #endregion const string rtfExtension = ".rtf"; FileName = fileName; Extension = extension; BufferSize = blockSize; _buffer = new char[ActBufferSize]; // ! Take into account that Rtf-file can be loaded only using IPersistFile. var doUseIPersistFile = string.Compare(rtfExtension, extension, StringComparison.InvariantCultureIgnoreCase) == 0; // Initialize _filter instance. try { if (doUseIPersistFile) { // Load content using IPersistFile. _filter = FilterLoader.LoadIFilterFromIPersistFile(FileName, Extension); } else { // Load content using IPersistStream. using (var stream = new FileStream(path: fileName, mode: FileMode.Open, access: FileAccess.Read, share: FileShare.Read)) { var buffer = new byte[stream.Length]; stream.Read(buffer, 0, buffer.Length); _filter = FilterLoader.LoadIFilterFromStream(buffer, Extension); } } } catch (FileNotFoundException) { throw; } catch (Exception e) { throw new AggregateException(message: string.Format("Filter Not Found or Loaded for extension '{0}'.", Extension), innerException: e); }