All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.linear.LinearThread Maven / Gradle / Ivy

/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2017 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
 @LICENSE@
 *
 * ---------------
 * LinearThread.java
 * ---------------
 */
package org.jpedal.linear;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import org.jpedal.FileAccess;
import org.jpedal.io.LinearizedHintTable;
import org.jpedal.io.PdfObjectReader;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.NumberUtils;

/**
 * handles download of rest of file in Linearized mode
 */
public class LinearThread extends Thread {

    public int percentageDone;

    final FileChannel fos;
    final PdfObject linearObj;
    final InputStream is;
    final File tempURLFile;
    final LinearizedHintTable linHintTable;

    final byte[] startObj = {'o', 'b', 'j'}, endObj = {'e', 'n', 'd', 'o', 'b', 'j'};
    int startCharReached, endCharReached;
    int startObjPtr, endObjPtr;

    //use top line to slow down load speed
    public static int bufSize = 8192;

    int ref;
    final int firstObjLength;

    final FileAccess fileAccess;

    final byte[] linearBytes;


    public LinearThread(final InputStream is, final FileChannel fos, final File tempURLFile, final PdfObject linearObj, final byte[] linearBytes, final LinearizedHintTable linHintTable, final FileAccess fileAccess) {

        this.fos = fos;
        this.linearObj = linearObj;
        this.is = is;
        this.tempURLFile = tempURLFile;
        this.linHintTable = linHintTable;

        this.linearBytes = linearBytes;

        this.fileAccess = fileAccess;

        //scan start of file for objects
        firstObjLength = linearBytes.length;

        scanStreamForObjects(0, null, linearBytes);

        this.setDaemon(true);

    }

    public int getPercentageLoaded() {
        return percentageDone;
    }

    @Override
    public void run() {

        final int linearfileLength = linearObj.getInt(PdfDictionary.L);

        try {

            int read, bytesRead = 0;

            //we cache last few bytes incase ref rolls across boundary
            byte[] lastBuffer = linearBytes; //new byte[lastBytes];

            byte[] buffer = new byte[bufSize];
            byte[] b;
            while ((read = is.read(buffer)) != -1 && !this.isInterrupted() && isAlive()) {

                if (read > 0) {
                    synchronized (fos) {

                        b = new byte[read];
                        System.arraycopy(buffer, 0, b, 0, read);
                        buffer = b;
                        final ByteBuffer f = ByteBuffer.wrap(b);
                        fos.write(f);
                    }
                }

                //track start endobj and flag so we know if object read
                if (read > 0) {
                    scanStreamForObjects(firstObjLength + bytesRead, lastBuffer, buffer);

                    bytesRead += read;

                    //save last few bytes incase of overlap
                    int aa = 30;

                    final int size1 = buffer.length;

                    if (aa > size1 - 1) {
                        aa = size1 - 1;
                    }

                    lastBuffer = new byte[aa];
                    System.arraycopy(buffer, size1 - aa, lastBuffer, 0, aa);
                }

                percentageDone = (int) (100 * (bytesRead / (float) linearfileLength));

                //debug code to simulate slow file stream by slowing down read of data from file
                // System.out.println("percentage="+percentageDone);
//                try {
//                    Thread.sleep(2000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }

            }

            linHintTable.setFinishedReading();


        } catch (final IOException e) {
            LogWriter.writeLog("Exception: " + e.getMessage());
        } finally {

            try {
                is.close();
                synchronized (fos) {
                    fos.close();
                }
                //possible that page still being decoded on slower machine so wait
                fileAccess.waitForDecodingToFinish();

                fileAccess.setIO(new PdfObjectReader());

                /* get reader object to open the file if all downloaded*/
                if (isAlive() && !isInterrupted()) {
                    fileAccess.openPdfFile(tempURLFile.getAbsolutePath());

                    /* store fi name for use elsewhere as part of ref key without .pdf */
                    fileAccess.getObjectStore().storeFileName(tempURLFile.getName().substring(0, tempURLFile.getName().lastIndexOf('.')));
                }

            } catch (final Exception e) {
                LogWriter.writeLog("Exception: " + e.getMessage());
            }
        }
    }

    private void scanStreamForObjects(final int bytesRead, final byte[] lastBuffer, final byte[] buffer) {

        final int bufSize = buffer.length;

        for (int i = 0; i < bufSize; i++) {

            if (startCharReached == 0) { //look for gap at start of obj
                if (buffer[i] == ' ' || buffer[i] == 0 || buffer[i] == 10 || buffer[i] == 32) {
                    startCharReached++;
                }
            } else if (startCharReached < 4) { //look for rest of obj

                if (buffer[i] == startObj[startCharReached - 1]) {

                    if (startCharReached == 3) { //start found so read object ref and log start

                        startObjPtr = bytesRead + i - 4;

                        //get the values
                        int ii = i - 4;

                        final byte[] data;

                        //add in last buffer to allow for crossing boundary
                        if (lastBuffer != null && ii < 30) {

                            final int size1 = lastBuffer.length;
                            final int size2 = buffer.length;
                            data = new byte[size1 + size2];
                            System.arraycopy(lastBuffer, 0, data, 0, size1);
                            System.arraycopy(buffer, 0, data, size1, size2);

                            ii += size1;

                        } else {
                            data = buffer;
                        }

                        int keyEnd = ii;

                        //generation value
                        while (data[ii] != 10 && data[ii] != 13 && data[ii] != 32 && data[ii] != 9) {
                            ii--;
                            startObjPtr--;
                        }

                        //generation
                        NumberUtils.parseInt(ii + 1, keyEnd, data);

                        //roll back to start of number
                        while (data[ii] == 10 || data[ii] == 13 || data[ii] == 32 || data[ii] == 47 || data[ii] == 60) {
                            ii--;
                            startObjPtr--;
                        }

                        keyEnd = ii + 1;

                        while (data[ii] != 10 && data[ii] != 13 && data[ii] != 32 && data[ii] != 47 && data[ii] != 60 && data[ii] != 62) {
                            ii--;
                            startObjPtr--;
                        }

                        ref = NumberUtils.parseInt(ii + 1, keyEnd, data);

                    }

                    startCharReached++;
                } else {
                    startCharReached = 0;
                }

            } else {
                if (buffer[i] == endObj[endCharReached]) {
                    endCharReached++;

                    if (endCharReached == 6) {
                        endObjPtr = bytesRead + i;

                        //currentPdfFile.storeOffset()
                        linHintTable.storeOffset(ref, startObjPtr, endObjPtr);

                        startCharReached = 0;
                        endCharReached = 0;
                    }
                } else {
                    endCharReached = 0;
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy