X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fjp%2Fsourceforge%2Fdvibrowser%2Fdvicore%2Fdoc%2FDirectFileDviDocument.java;fp=src%2Fmain%2Fjava%2Fjp%2Fsourceforge%2Fdvibrowser%2Fdvicore%2Fdoc%2FDirectFileDviDocument.java;h=b0c12584321d9d33b3cb3510748bd267b5cf8e7a;hb=93efc067c74bbead8d4e430193690888da0e49c2;hp=0000000000000000000000000000000000000000;hpb=df94a623b684b25842e0a18636bbaa284feb88e2;p=dvibrowser%2Fdvi2epub.git diff --git a/src/main/java/jp/sourceforge/dvibrowser/dvicore/doc/DirectFileDviDocument.java b/src/main/java/jp/sourceforge/dvibrowser/dvicore/doc/DirectFileDviDocument.java new file mode 100644 index 0000000..b0c1258 --- /dev/null +++ b/src/main/java/jp/sourceforge/dvibrowser/dvicore/doc/DirectFileDviDocument.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2009, Takeyuki Nagao + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +package jp.sourceforge.dvibrowser.dvicore.doc; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; + +import jp.sourceforge.dvibrowser.dvicore.DviConstants; +import jp.sourceforge.dvibrowser.dvicore.DviException; +import jp.sourceforge.dvibrowser.dvicore.DviFontSpec; +import jp.sourceforge.dvibrowser.dvicore.DviFontTable; +import jp.sourceforge.dvibrowser.dvicore.DviObject; +import jp.sourceforge.dvibrowser.dvicore.DviUnit; +import jp.sourceforge.dvibrowser.dvicore.api.DviContextSupport; +import jp.sourceforge.dvibrowser.dvicore.api.DviDocument; +import jp.sourceforge.dvibrowser.dvicore.api.DviInput; +import jp.sourceforge.dvibrowser.dvicore.api.DviPage; +import jp.sourceforge.dvibrowser.dvicore.api.HasURL; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviCommand; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostPost; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPostamble; +import jp.sourceforge.dvibrowser.dvicore.cmd.DviPreamble; +import jp.sourceforge.dvibrowser.dvicore.io.ByteArrayDviData; +import jp.sourceforge.dvibrowser.dvicore.io.DviRandomAccessFileInput; +import jp.sourceforge.dvibrowser.dvicore.render.EmptyDviExecutorHandler; + + +// TODO: Optimize this class. It's really slow for a large file. +public class DirectFileDviDocument +extends DviObject +implements DviDocument, HasURL +{ + public static final long MAX_BUFFER_LENGTH = 10000000; + /* Buffer size for the data after postamble. 10MB */ + + private final File file; + + private DviPreamble preamble = null; + private DviPostamble postamble = null; + private DviPostPost postPost = null; + + final DviFontTable fontTable = new DviFontTable(); + + private ArrayList pages = new ArrayList(); + + public DirectFileDviDocument(DviContextSupport dcs, File file) + throws DviException + { + super(dcs); + this.file = file; + try { + RandomAccessFile in = new RandomAccessFile(file, "r"); + parseRandomAccessFile(in); + in.close(); + } catch (IOException ex) { + throw new DviException(ex); + } + } + + private void parseRandomAccessFile(RandomAccessFile in) + throws IOException, DviException + { + // Parse the preamble. + { + int idByte, num, den, mag, k; + byte [] comment; + + if (DviCommand.DVI_PRE != in.readUnsignedByte()) + throw new DviException + ("Format error in dvi file: file doesn't start with pre."); + + idByte = in.readUnsignedByte(); + num = in.readInt(); + den = in.readInt(); + mag = in.readInt(); + + k = in.readUnsignedByte(); + comment = new byte[k]; + in.readFully(comment); + + preamble = new DviPreamble( + idByte, DviUnit.getInstance(num, den, mag), comment); + } + + // Determine the location of the postamble. + final long postPostPointer; + { + long pos = in.length() - 1; + int postamblePointer; + int idByte; + + long paddingSize = 0; + + while (true) { + if (pos < 0) + throw new DviException( + "Dvi file ended while looking for the postamble."); + in.seek(pos); + if (DviConstants.DVI_TRAILER != in.readUnsignedByte()) break; + paddingSize++; + pos--; + } + pos -= 5; + if (pos < 0) + throw new DviException( + "Dvi file ended while looking for the postamble."); + + postPostPointer = pos; + + /* pos -> +0 DVI_POST_POST (U1) + * +1 post_offset (U4) + * +5 id_byte (U1) + * +6 padding paddingSize copies of ((byte)223). + */ + in.seek(pos); + + if (DviCommand.DVI_POST_POST != in.readUnsignedByte()) + throw new DviException( + "Format error in dvi file: unable to find post_post."); + + postamblePointer = in.readInt(); + if (postamblePointer < 0 || + (long) postamblePointer > in.length() - 33) + throw new DviException( + "Format error in dvi file: file size too short."); + + /* TODO: check id_byte */ + idByte = in.readUnsignedByte(); + + postPost = new DviPostPost(postamblePointer, idByte); + } + + in.seek(postPost.postamblePointer()); + + /* pos -> + 0 DVI_POST (U1) + * + 1 bp (S4) + * + 5 num (S4) + * + 9 den (S4) + * +13 mag (S4) + * +17 maxV (S4) + * +21 maxH (S4) + * +25 max_stack_depth (U2) + * +27 total_pages (U2) + * size = 29 bytes. + */ + + if (DviCommand.DVI_POST != in.readUnsignedByte()) + throw new DviException( + "Format error in dvi file: unable to find post."); + + { + int bp; + int num, den, mag; + int maxV, maxH, maxStackDepth, totalPages; + + bp = in.readInt(); + num = in.readInt(); + den = in.readInt(); + mag = in.readInt(); + maxV = in.readInt(); + maxH = in.readInt(); + maxStackDepth = in.readUnsignedShort(); + totalPages = in.readUnsignedShort(); + + postamble = new DviPostamble( + bp, DviUnit.getInstance(num, den, mag), + maxV, maxH, maxStackDepth, totalPages); + } + + // parse font definitions stored right after the postamble. + + { + long buflen = postPostPointer - in.getFilePointer(); + if (0 < buflen) { + if (buflen > MAX_BUFFER_LENGTH) + throw new DviException + ("Too long data after postamble."); + + final byte [] buf = new byte [(int) buflen]; + in.readFully(buf); + + getDviContext().execute( + new ByteArrayDviData(buf), + new EmptyDviExecutorHandler() { + public void doDefineFont(int fn, DviFontSpec fs) { + fontTable.put(fn, fs); + } + } + ); + } + } + + // TODO: handle embedded data. + + { + long bop = postamble.firstBackPointer(); + long eop = postPost.postamblePointer() - 1; + int pageNum = postamble.totalPages(); + + while (bop != -1 && pageNum > 0) { + in.seek(bop); + + if (DviCommand.DVI_BOP != in.readUnsignedByte()) + throw new DviException( + "Format error in dvi file: broken bop link."); + + pageNum--; + // REMARK: pageNum==0 corresponds to the first page. + pages.add(0, new DefaultDviPage(DirectFileDviDocument.this, pageNum, bop, eop)); + + eop = bop - 1; + in.seek(bop + 1 + 4 * 10); + bop = in.readInt(); + } + + if (pageNum != 0) + throw new DviException( + "Format error in dvi file: wrong number of pages."); + } + } + + public int getTotalPages() throws DviException { + return postamble.totalPages(); + } + + public DviUnit getDviUnit() { + return postamble.dviUnit(); + } + public DviPreamble getPreamble() { + return preamble; + } + public DviPostamble getPostamble() { + return postamble; + } + public DviPostPost getPostPost() { + return postPost; + } + public DviFontTable getFontTable() { + return fontTable; + } + + public DviInput getInput() + throws DviException + { + try { + RandomAccessFile raf = new RandomAccessFile(getFile(), "r"); + DviRandomAccessFileInput in = new DviRandomAccessFileInput(raf); + return in; + } catch (FileNotFoundException e) { + throw new DviException(e); + } + } + + public DviInput getInput(long start, long end) throws DviException + { + try { + RandomAccessFile raf = new RandomAccessFile(getFile(), "r"); + raf.seek(start); + DviRandomAccessFileInput in = new DviRandomAccessFileInput(raf); + in.setOffset(start); + in.setEnd(end); + return in; + } catch (FileNotFoundException e) { + throw new DviException(e); + } catch (IOException e) { + throw new DviException(e); + } + } + +// private DviInput getInputNIO(long start, long end) +// throws DviException +// { +// try { +// FileInputStream fis = new FileInputStream(file); +// FileChannel fc = fis.getChannel(); +// MappedByteBuffer bb = fc.map( +// FileChannel.MapMode.READ_ONLY, +// start, end - start + 1 +// ); +// DviByteBufferInput in = new DviByteBufferInput(bb); +// in.setOffset(start); +// return in; +// } catch (Throwable ex) { +// Logger.trace(ex); +// return getInput(start, end); +// } +// } + + public DviPage getPage(int p) + throws DviException + { + if (p < 0 || getTotalPages() <= p) + throw new IllegalArgumentException + ("page number out of bounds."); + + return pages.get(p); + } + + public DviPage [] getPages() + { + return pages.toArray(new DviPage [0]); + } + + public long getDataSize() throws DviException + { + return getFile().length(); + } + + public File getFile() + { + return file; + } + + public URL getURL() throws DviException + { + try { + return file.toURL(); + } catch (MalformedURLException e) { + throw new DviException(e); + } + } +}