package org.jnode.fs.hfsplus.compression; import java.io.IOException; import java.nio.ByteBuffer; import org.jnode.fs.hfsplus.HfsPlusFile; import org.jnode.fs.hfsplus.HfsPlusFileSystem; import org.jnode.fs.hfsplus.attributes.AttributeData; /** * Attribute stored LZVN compressed data. * * @author Luke Quinane */ public class AttributeLzvnCompression implements HfsPlusCompression { /** * The attribute data to read in. */ private final AttributeData attributeData; /** * The decompression header. */ private final DecmpfsDiskHeader decmpfsDiskHeader; /** * The uncompressed copy of the data. */ private ByteBuffer uncompressed; /** * Creates a new instance. * * @param attributeData the attribute data to read from. * @param decmpfsDiskHeader the decompression header. */ public AttributeLzvnCompression(AttributeData attributeData, DecmpfsDiskHeader decmpfsDiskHeader) { this.attributeData = attributeData; this.decmpfsDiskHeader = decmpfsDiskHeader; } @Override public void read(HfsPlusFileSystem fs, long fileOffset, ByteBuffer dest) throws IOException { if (uncompressed == null) { ByteBuffer compressed = ByteBuffer.allocate((int) attributeData.getSize() - DecmpfsDiskHeader.LENGTH); attributeData.read(fs, DecmpfsDiskHeader.LENGTH, compressed); uncompressed = ByteBuffer.allocate((int) decmpfsDiskHeader.getUncompressedSize()); if (compressed.array()[0] == (byte) 0xff) { // 0xff seems to be a marker for uncompressed data. Skip this byte any just copy the data out. // I have no idea why they didn't use 'CMP_Type1' which is meant for uncompressed data according to the // headers compressed.position(1); uncompressed.put(compressed); } else { LzvnForkCompression.lzvnDecode(compressed, uncompressed); } } uncompressed.position((int) fileOffset); uncompressed.limit(Math.min(uncompressed.capacity(), uncompressed.position() + dest.remaining())); dest.put(uncompressed); } /** * The factory for this compression type. */ public static class Factory implements HfsPlusCompressionFactory { @Override public HfsPlusCompression createDecompressor(HfsPlusFile file, AttributeData attributeData, DecmpfsDiskHeader decmpfsDiskHeader) { return new AttributeLzvnCompression(attributeData, decmpfsDiskHeader); } } }