CompoundDocument(final SeekableInputStream stream) throws IOException { input = new SeekableLittleEndianDataInputStream(stream); // TODO: Might be better to read header on first read operation?! // OTOH: It's also good to be fail-fast, so at least we should make // sure we're reading a valid document readHeader(); }
public Entry getRootEntry() throws IOException { if (rootEntry == null) { readSAT(); rootEntry = getEntry(0, null); if (rootEntry.type != Entry.ROOT_STORAGE) { throw new CorruptDocumentException("Invalid root storage type: " + rootEntry.type); } } return rootEntry; }
/** * Reads an entry from the input. * * @param pInput the input data * @return the {@code Entry} read from the input data * @throws IOException if an i/o exception occurs during reading */ static Entry readEntry(final DataInput pInput) throws IOException { Entry p = new Entry(); p.read(pInput); return p; }
@Test public void testRoot() throws IOException { try (CompoundDocument document = createTestDocument()) { Entry root = document.getRootEntry(); assertNotNull(root); assertEquals("Root Entry", root.getName()); assertTrue(root.isRoot()); assertFalse(root.isFile()); assertFalse(root.isDirectory()); assertEquals(0, root.length()); assertNull(root.getInputStream()); } }
@Test public void testReadThumbsCatalogFile() throws IOException { try (CompoundDocument document = createTestDocument()) { Entry root = document.getRootEntry(); assertNotNull(root); assertEquals(25, root.getChildEntries().size()); Entry catalog = root.getChildEntry("Catalog"); assertNotNull(catalog); assertNotNull("Input stream may not be null", catalog.getInputStream()); } }
private void initCatalog() throws IOException { if (catalog == null) { Entry catalog = root.getChildEntry("Catalog"); if (catalog.length() <= 16L) { // TODO: Throw exception? Return empty catalog? } this.catalog = Catalog.read(catalog.getInputStream()); } }
@Test(expected = UnsupportedOperationException.class) public void testChildEntriesUnmodifiable() throws IOException { try (CompoundDocument document = createTestDocument()) { Entry root = document.getRootEntry(); assertNotNull(root); SortedSet<Entry> children = root.getChildEntries(); // Should not be allowed, as it modifies the internal structure children.remove(children.first()); } }
/** * Gets the SIdChain for the given stream Id * * @param pSId the stream Id * @param pStreamSize the size of the stream, or -1 for system control streams * @return the SIdChain for the given stream Id * @throws IOException if an I/O exception occurs */ private SIdChain getSIdChain(final int pSId, final long pStreamSize) throws IOException { SIdChain chain = new SIdChain(); int[] sat = isShortStream(pStreamSize) ? shortSAT : SAT; int sid = pSId; while (sid != END_OF_CHAIN_SID && sid != FREE_SID) { chain.addSID(sid); sid = sat[sid]; } return chain; }
/** * Returns the {@code InputStream} for this {@code Entry} * * @return an {@code InputStream} containing the data for this * {@code Entry} or {@code null} if this is a directory {@code Entry} * @throws java.io.IOException if an I/O exception occurs * @see #length() */ public SeekableInputStream getInputStream() throws IOException { if (!isFile()) { return null; } return document.getInputStreamForSId(startSId, streamSize); }
public int read() throws IOException { if (available() <= 0) { if (!fillBuffer()) { return -1; } } streamPos++; return buffer[bufferPos++] & 0xff; }
SeekableInputStream getInputStreamForSId(final int pStreamId, final int pStreamSize) throws IOException { SIdChain chain = getSIdChain(pStreamId, pStreamSize); // TODO: Detach? Means, we have to copy to a byte buffer, or keep track of // positions, and seek back and forth (would be cool, but difficult).. int sectorSize = pStreamSize < minStreamSize ? shortSectorSize : this.sectorSize; return new MemoryCacheSeekableStream(new Stream(chain, pStreamSize, sectorSize, this)); }
Entry getEntry(final int pDirectoryId, Entry pParent) throws IOException { Entry entry = Entry.readEntry(new LittleEndianDataInputStream( getDirectoryStreamForDId(pDirectoryId) )); entry.parent = pParent; entry.document = this; return entry; }
/** * Returns the length of this entry * * @return the length of the stream for this entry, or {@code 0} if this is * a directory {@code Entry} * @see #getInputStream() */ public long length() { if (!isFile()) { return 0L; } return streamSize; }
public static boolean canRead(final DataInput pInput) { return canRead(pInput, true); }
@Override public boolean equals(final Object pOther) { if (pOther == this) { return true; } if (!(pOther instanceof Entry)) { return false; } Entry other = (Entry) pOther; return name.equals(other.name) && (parent == other.parent || (parent != null && parent.equals(other.parent))); }
void addSID(int pSID) { ensureCapacity(); chain[size++] = pSID; }
public CorruptDocumentException(final Throwable pCause) { super(pCause.getMessage()); initCause(pCause); } }
e = new Entry(); e.set({title: "my blog rulez", body: "this is the best blog evar!!!!1!!"}); e.save();
boolean canDecode(final ImageInputStream pInput) throws IOException { maybeInitJPEGProvider(); // If this is a OLE 2 CompoundDocument, we could try... // TODO: How do we know it's thumbs.db format (structure), without reading quite a lot? return jpegProvider != null && CompoundDocument.canRead(pInput); }