package org.ebookdroid.common.cache; import org.ebookdroid.core.Page; import org.ebookdroid.core.codec.CodecPageInfo; import android.graphics.RectF; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import org.emdev.common.log.LogContext; import org.emdev.utils.collections.SparseArrayEx; public class DocumentCacheFile extends File { private static final int TAG_PAGE_COUNTS = 0; private static final int TAG_CODEC_PAGE_INFO = 1; private static final int TAG_AUTO_CROPPING = 2; private static final int TAG_MANUAL_CROPPING = 3; private static final long serialVersionUID = 6836895806027391288L; private static final LogContext LCTX = CacheManager.LCTX; DocumentCacheFile(final File dir, final String name) { super(dir, name); } public DocumentInfo load() { try { LCTX.d("Loading document info..."); final DocumentInfo info = new DocumentInfo(); final DataInputStream in = new DataInputStream(new FileInputStream(this)); try { while (true) { byte tag = -1; try { tag = in.readByte(); } catch (EOFException ex) { return info; } final byte id = (byte) (tag & 0x3F); final boolean docPage = (tag & 0x80) == 0; final boolean leftPage = (tag & 0x40) == 0; switch (id) { case TAG_PAGE_COUNTS: // Number of pages info.loadPageCounts(in); break; case TAG_CODEC_PAGE_INFO: // CodecPageInfo - only for docs info.loadCodePageInfo(in); break; case TAG_AUTO_CROPPING: // Auto cropping info.loadAutoCropping(in, docPage, leftPage); break; case TAG_MANUAL_CROPPING: // Manual cropping info.loadManualCropping(in, docPage, leftPage); break; } } } catch (final EOFException ex) { LCTX.e("Loading document info failed: " + ex.getMessage()); } catch (final IOException ex) { LCTX.e("Loading document info failed: " + ex.getMessage()); } finally { try { in.close(); } catch (final IOException ex) { } } } catch (final FileNotFoundException ex) { LCTX.e("Loading document info failed: " + ex.getMessage()); } return null; } public void save(final DocumentInfo info) { try { LCTX.d("Saving document info..."); final DataOutputStream out = new DataOutputStream(new FileOutputStream(this)); try { info.savePageCounts(out); info.saveCodePageInfo(out); info.saveAutoCropping(out); info.saveManualCropping(out); LCTX.d("Saving document info finished"); } catch (final IOException ex) { LCTX.e("Saving document info failed: " + ex.getMessage()); } finally { try { out.close(); } catch (final IOException ex) { } } } catch (final IOException ex) { LCTX.e("Saving document info failed: " + ex.getMessage()); } } public static class DocumentInfo { public int docPageCount; public int viewPageCount; public final SparseArrayEx<PageInfo> docPages = new SparseArrayEx<PageInfo>(); public final SparseArrayEx<PageInfo> leftPages = new SparseArrayEx<PageInfo>(); public final SparseArrayEx<PageInfo> rightPages = new SparseArrayEx<PageInfo>(); void loadPageCounts(final DataInputStream in) throws IOException { this.docPageCount = in.readShort(); this.viewPageCount = in.readShort(); } void savePageCounts(final DataOutputStream out) throws IOException { out.writeByte(TAG_PAGE_COUNTS); out.writeShort(this.docPageCount); out.writeShort(this.viewPageCount); } void loadCodePageInfo(final DataInputStream in) throws IOException { final int index = in.readShort(); PageInfo pageInfo = this.docPages.get(index, null); if (pageInfo == null) { pageInfo = new PageInfo(index); this.docPages.append(index, pageInfo); } pageInfo.info = new CodecPageInfo(in.readInt(), in.readInt()); } void saveCodePageInfo(final DataOutputStream out) throws IOException { for (final PageInfo info : this.docPages) { if (info.info != null) { out.writeByte(TAG_CODEC_PAGE_INFO); out.writeShort(info.index); out.writeInt(info.info.width); out.writeInt(info.info.height); } } } void loadAutoCropping(final DataInputStream in, final boolean docPage, final boolean leftPage) throws IOException { final int index = in.readShort(); final SparseArrayEx<PageInfo> target = getPages(docPage, leftPage); PageInfo pageInfo = target.get(index, null); if (pageInfo == null) { pageInfo = new PageInfo(index); target.append(index, pageInfo); } pageInfo.autoCropping = new RectF(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat()); } void loadManualCropping(final DataInputStream in, final boolean docPage, final boolean leftPage) throws IOException { final int index = in.readShort(); final SparseArrayEx<PageInfo> target = getPages(docPage, leftPage); PageInfo pageInfo = target.get(index, null); if (pageInfo == null) { pageInfo = new PageInfo(index); target.append(index, pageInfo); } pageInfo.manualCropping = new RectF(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat()); } void saveAutoCropping(final DataOutputStream out) throws IOException { for (final PageInfo info : this.docPages) { final RectF cropping = info.autoCropping; if (cropping != null) { saveCropping(out, TAG_AUTO_CROPPING, info.index, cropping); } } for (final PageInfo info : this.leftPages) { final RectF cropping = info.autoCropping; if (cropping != null) { saveCropping(out, TAG_AUTO_CROPPING | 0x80, info.index, cropping); } } for (final PageInfo info : this.rightPages) { final RectF cropping = info.autoCropping; if (cropping != null) { saveCropping(out, TAG_AUTO_CROPPING | 0x80 | 0x40, info.index, cropping); } } } void saveManualCropping(final DataOutputStream out) throws IOException { for (final PageInfo info : this.docPages) { final RectF cropping = info.manualCropping; if (cropping != null) { saveCropping(out, TAG_MANUAL_CROPPING, info.index, cropping); } } for (final PageInfo info : this.leftPages) { final RectF cropping = info.manualCropping; if (cropping != null) { saveCropping(out, TAG_MANUAL_CROPPING | 0x80, info.index, cropping); } } for (final PageInfo info : this.rightPages) { final RectF cropping = info.manualCropping; if (cropping != null) { saveCropping(out, TAG_MANUAL_CROPPING | 0x80 | 0x40, info.index, cropping); } } } void saveCropping(final DataOutputStream out, final int tag, final int index, final RectF cropping) throws IOException { out.writeByte(tag); out.writeShort(index); out.writeFloat(cropping.left); out.writeFloat(cropping.top); out.writeFloat(cropping.right); out.writeFloat(cropping.bottom); } SparseArrayEx<PageInfo> getPages(final boolean docPage, final boolean leftPage) { return docPage ? this.docPages : leftPage ? this.leftPages : this.rightPages; } public PageInfo getPageInfo(Page page) { SparseArrayEx<PageInfo> arr = null; switch (page.type) { case FULL_PAGE: arr = docPages; break; case LEFT_PAGE: arr = leftPages; break; case RIGHT_PAGE: arr = rightPages; break; } int key = page.index.docIndex; PageInfo pi = arr.get(key, null); if (pi == null) { pi = new PageInfo(key); arr.append(key, pi); } return pi; } } public static class PageInfo { public final int index; public CodecPageInfo info; public RectF autoCropping; public RectF manualCropping; public PageInfo(final int index) { this.index = index; } } }