forked from geodmms/xdgnjobs

Dennis Kao
2014-01-15 94ae08701bbd7585a0b7e5a92d1975965a503c03
xdgnjobs/ximple-dgnio/src/main/java/com/ximple/io/dgn7/Dgn7fileReader.java
@@ -2,6 +2,8 @@
//~--- JDK imports ------------------------------------------------------------
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
@@ -11,8 +13,6 @@
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
@@ -27,10 +27,9 @@
 *
 * @author Ulysses
 * @version 0.1
 * @since 2006/5/17 ¤U¤È 01:24:10
 * @since 2006/5/17
 */
public class Dgn7fileReader
{
public class Dgn7fileReader {
    private static final Logger logger = LogManager.getLogger(Dgn7fileReader.class);
    private Dgn7fileHeader header;
@@ -38,17 +37,16 @@
    ByteBuffer buffer;
    private ElementType fileElementType = ElementType.UNDEFINED;
    private ByteBuffer headerTransfer;
    private final Record record = new Record();
    private final Element.FileRecord record = new Element.FileRecord();
    private final boolean randomAccessEnabled;
    private Lock lock;
    private boolean useMemoryMappedBuffer;
    private long currentOffset = 0L;
    private StreamLogging streamLogger = new StreamLogging("Shapefile Reader");
    private StreamLogging streamLogger = new StreamLogging("Dgn7 Reader");
    private int maxElementId = 0;
    public Dgn7fileReader(ReadableByteChannel channel, boolean strict, boolean useMemoryMapped, Lock lock)
            throws IOException, Dgn7fileException
    {
    public Dgn7fileReader(FileChannel channel, boolean strict, boolean useMemoryMapped, Lock lock)
        throws IOException, Dgn7fileException {
        this.channel = channel;
        this.useMemoryMappedBuffer = useMemoryMapped;
        streamLogger.open();
@@ -58,34 +56,29 @@
        init(strict);
    }
    public Dgn7fileReader(ReadableByteChannel channel, Lock lock) throws IOException, Dgn7fileException
    {
    public Dgn7fileReader(FileChannel channel, Lock lock) throws IOException, Dgn7fileException {
        this(channel, true, true, lock);
    }
    // ensure the capacity of the buffer is of size by doubling the original
    // capacity until it is big enough
    // this may be naiive and result in out of MemoryError as implemented...
    public static ByteBuffer ensureCapacity(ByteBuffer buffer, int size, boolean useMemoryMappedBuffer)
    {
    public static ByteBuffer ensureCapacity(ByteBuffer buffer, int size, boolean useMemoryMappedBuffer) {
        // This sucks if you accidentally pass is a MemoryMappedBuffer of size
        // 80M
        // like I did while messing around, within moments I had 1 gig of
        // swap...
        if (buffer.isReadOnly() || useMemoryMappedBuffer)
        {
        if (buffer.isReadOnly() || useMemoryMappedBuffer) {
            return buffer;
        }
        int limit = buffer.limit();
        while (limit < size)
        {
        while (limit < size) {
            limit *= 2;
        }
        if (limit != buffer.limit())
        {
        if (limit != buffer.limit()) {
            // if (record.ready) {
            buffer = ByteBuffer.allocateDirect(limit);
@@ -99,31 +92,26 @@
    }
    // for filling a ReadableByteChannel
    public static int fill(ByteBuffer buffer, ReadableByteChannel channel) throws IOException
    {
    public static int fill(ByteBuffer buffer, ReadableByteChannel channel) throws IOException {
        int r = buffer.remaining();
        // channel reads return -1 when EOF or other error
        // because they a non-blocking reads, 0 is a valid return value!!
        while ((buffer.remaining() > 0) && (r != -1))
        {
        while ((buffer.remaining() > 0) && (r != -1)) {
            r = channel.read(buffer);
        }
        if (r == -1)
        {
        if (r == -1) {
            buffer.limit(buffer.position());
        }
        return r;
    }
    public static Dgn7fileHeader readHeader(ReadableByteChannel channel, boolean strict) throws IOException
    {
    public static Dgn7fileHeader readHeader(ReadableByteChannel channel, boolean strict) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocateDirect(4);
        if (fill(buffer, channel) == -1)
        {
        if (fill(buffer, channel) == -1) {
            throw new EOFException("Premature end of header");
        }
@@ -138,8 +126,7 @@
        buffer = ByteBuffer.allocateDirect(length + 4);
        buffer.put(old);
        if (fill(buffer, channel) == -1)
        {
        if (fill(buffer, channel) == -1) {
            throw new EOFException("Premature end of header");
        }
@@ -152,23 +139,19 @@
        return header;
    }
    public Dgn7fileHeader getHeader()
    {
    public Dgn7fileHeader getHeader() {
        return header;
    }
    public void close() throws IOException
    {
    public void close() throws IOException {
        lock.unlockRead();
        if (channel.isOpen())
        {
        if (channel.isOpen()) {
            channel.close();
            streamLogger.close();
        }
        if (buffer instanceof MappedByteBuffer)
        {
        if (buffer instanceof MappedByteBuffer) {
            NIOUtilities.clean(buffer);
        }
@@ -176,13 +159,11 @@
        header = null;
    }
    public boolean supportsRandomAccess()
    {
    public boolean supportsRandomAccess() {
        return randomAccessEnabled;
    }
    public Record nextElement() throws IOException, Dgn7fileException
    {
    public Element.FileRecord nextElement() throws IOException, Dgn7fileException {
        // need to update position
        buffer.position(this.toBufferOffset(record.end));
@@ -201,12 +182,10 @@
        // track the record location
        int elementLength = (buffer.getShort() * 2) + 4;
        if (!buffer.isReadOnly() && !useMemoryMappedBuffer)
        {
        if (!buffer.isReadOnly() && !useMemoryMappedBuffer) {
            // capacity is less than required for the record
            // copy the old into the newly allocated
            if (buffer.capacity() < elementLength)
            {
            if (buffer.capacity() < elementLength) {
                this.currentOffset += buffer.position();
                ByteBuffer old = buffer;
@@ -221,8 +200,7 @@
                // remaining is less than record length
                // compact the remaining data and read again,
                // allowing enough room for one more record header
                if (buffer.remaining() < elementLength)
                {
                if (buffer.remaining() < elementLength) {
                    this.currentOffset += buffer.position();
                    buffer.compact();
                    fill(buffer, channel);
@@ -252,8 +230,7 @@
        // second guess them...
        buffer.mark();
        if (recordType.isMultiPoint())
        {
        if (recordType.isMultiPoint()) {
            int lowCoorX = buffer.getInt();
            lowCoorX = DgnUtility.convertFromDGN(lowCoorX);
@@ -292,6 +269,7 @@
        record.length = elementLength;
        record.signature = signature;
        record.number = recordNumber;
        record.buffer = buffer;
        // remember, we read one int already...
        record.end = this.toFileOffset(buffer.position()) + elementLength - 4;
@@ -307,24 +285,18 @@
        return record;
    }
    public void goTo(int offset) throws IOException, UnsupportedOperationException
    {
        if (randomAccessEnabled)
        {
            if (this.useMemoryMappedBuffer)
            {
    public void goTo(int offset) throws IOException, UnsupportedOperationException {
        if (randomAccessEnabled) {
            if (this.useMemoryMappedBuffer) {
                buffer.position(offset);
            } else
            {
            } else {
                /*
                 *     Check to see if requested offset is already loaded; ensure
                 *     that record header is in the buffer
                 */
                if ((this.currentOffset <= offset) && (this.currentOffset + buffer.limit() >= offset + 4))
                {
                if ((this.currentOffset <= offset) && (this.currentOffset + buffer.limit() >= offset + 4)) {
                    buffer.position(this.toBufferOffset(offset));
                } else
                {
                } else {
                    FileChannel fc = (FileChannel) this.channel;
                    fc.position(offset);
@@ -339,25 +311,20 @@
            record.end = offset;
            try
            {
            try {
                hasNext();
            } catch (IOException ioe)
            {
            } catch (IOException ioe) {
                record.end = oldRecordOffset;
                throw ioe;
            }
        } else
        {
        } else {
            throw new UnsupportedOperationException("Random Access not enabled");
        }
    }
    public Record elementAt(int offset) throws IOException, UnsupportedOperationException, Dgn7fileException
    {
        if (randomAccessEnabled)
        {
    public Element.FileRecord elementAt(int offset) throws IOException, UnsupportedOperationException, Dgn7fileException {
        if (randomAccessEnabled) {
            this.goTo(offset);
            return nextElement();
@@ -366,25 +333,21 @@
        throw new UnsupportedOperationException("Random Access not enabled");
    }
    public boolean hasNext() throws IOException
    {
    public boolean hasNext() throws IOException {
        // mark current position
        int position = buffer.position();
        // ensure the proper position, regardless of read or handler behavior
        try
        {
        try {
            buffer.position(this.toBufferOffset(record.end));
        } catch (IllegalArgumentException e)
        {
        } catch (IllegalArgumentException e) {
            logger.warn("position=" + this.toBufferOffset(record.end), e);
            return false;
        }
        // no more data left
        if (buffer.remaining() < 4)
        {
        if (buffer.remaining() < 4) {
            return false;
        }
@@ -392,8 +355,7 @@
        boolean hasNext = true;
        short type = buffer.getShort();
        if (type == -1)
        {
        if (type == -1) {
            hasNext = false;
        }
@@ -403,8 +365,7 @@
        return hasNext;
    }
    private void init(boolean strict) throws IOException, Dgn7fileException
    {
    private void init(boolean strict) throws IOException, Dgn7fileException {
        header = readHeader(channel, strict);
        // fileElementType = header.getElementType();
@@ -416,8 +377,7 @@
        // {
        // throw new IOException("Unsuported shape type:" + fileElementType);
        // }
        if ((channel instanceof FileChannel) && useMemoryMappedBuffer)
        {
        if ((channel instanceof FileChannel) && useMemoryMappedBuffer) {
            FileChannel fc = (FileChannel) channel;
            buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
@@ -425,8 +385,7 @@
            // buffer.position(100);
            buffer.position(header.size());
            this.currentOffset = 0;
        } else
        {
        } else {
            // force useMemoryMappedBuffer to false
            this.useMemoryMappedBuffer = false;
@@ -444,33 +403,26 @@
        record.end = toFileOffset(buffer.position());
    }
    private int toBufferOffset(int offset)
    {
    private int toBufferOffset(int offset) {
        return (int) (offset - currentOffset);
    }
    private int toFileOffset(int offset)
    {
    private int toFileOffset(int offset) {
        return (int) (currentOffset + offset);
    }
    public int getCount(int count) throws Dgn7fileException
    {
        try
        {
            if (channel == null)
            {
    public int getCount(int count) throws Dgn7fileException {
        try {
            if (channel == null) {
                return -1;
            }
            count = 0;
            for (int tmp = readElement(); tmp != -1; tmp = readElement())
            {
            for (int tmp = readElement(); tmp != -1; tmp = readElement()) {
                count += tmp;
            }
        } catch (IOException ioe)
        {
        } catch (IOException ioe) {
            count = -1;
            // What now? This seems arbitrarily appropriate !
@@ -480,23 +432,19 @@
        return count;
    }
    public int getCount() throws Dgn7fileException
    {
    public int getCount() throws Dgn7fileException {
        return getCount(0);
    }
    private int readElement() throws IOException
    {
        if (!fillBuffer())
        {
    private int readElement() throws IOException {
        if (!fillBuffer()) {
            return -1;
        }
        // burn the record number
        buffer.getInt();
        if (!fillBuffer())
        {
        if (!fillBuffer()) {
            return -1;
        }
@@ -506,8 +454,7 @@
        // subtract that from the record length
        recordlength -= 4;
        if (!fillBuffer())
        {
        if (!fillBuffer()) {
            return -1;
        }
@@ -515,13 +462,11 @@
        int type = buffer.getInt();
        // go to end of record
        while (buffer.limit() < buffer.position() + recordlength)
        {
        while (buffer.limit() < buffer.position() + recordlength) {
            recordlength -= buffer.limit() - buffer.position();
            buffer.clear();
            if (channel.read(buffer) < 1)
            {
            if (channel.read(buffer) < 1) {
                return -1;
            }
        }
@@ -529,8 +474,7 @@
        buffer.position(buffer.position() + recordlength);
        // return 0 if record is null. Null records should be counted.
        if (type == 0)
        {
        if (type == 0) {
            // this is a null feature
            return 0;
        }
@@ -538,28 +482,23 @@
        return 1;
    }
    private boolean fillBuffer() throws IOException
    {
    private boolean fillBuffer() throws IOException {
        int result = 1;
        if (buffer.limit() <= buffer.position() + 4)
        {
        if (buffer.limit() <= buffer.position() + 4) {
            result = fill(buffer, channel);
        }
        return result > 0;
    }
    public static void main(String[] args)
    {
    public static void main(String[] args) {
        JFileChooser jfc = new JFileChooser("D:/TEMP");
        File f = null;
        int r = jfc.showOpenDialog(new JFrame());
        if (r == JFileChooser.APPROVE_OPTION)
        {
            try
            {
        if (r == JFileChooser.APPROVE_OPTION) {
            try {
                f = jfc.getSelectedFile();
                FileChannel channel = new FileInputStream(f).getChannel();
@@ -573,25 +512,20 @@
                count = 0;
                size = 0;
                try
                {
                try {
                    Element lastComplex = null;
                    while (reader.hasNext())
                    {
                    while (reader.hasNext()) {
                        size++;
                        Dgn7fileReader.Record record = reader.nextElement();
                        Element.FileRecord record = reader.nextElement();
                        if (record.element() != null)
                        {
                        if (record.element() != null) {
                            Element element = (Element) record.element();
                            ElementType type = element.getElementType();
                            if ((!type.isComplexElement()) && (!element.isComponentElement()))
                            {
                                if (lastComplex != null)
                                {
                            if ((!type.isComplexElement()) && (!element.isComponentElement())) {
                                if (lastComplex != null) {
                                    // @todo add process in here
                                    count++;
                                    lastComplex = null;
@@ -599,19 +533,14 @@
                                // @todo add process in here
                                count++;
                            } else if (element.isComponentElement())
                            {
                                if (lastComplex != null)
                                {
                            } else if (element.isComponentElement()) {
                                if (lastComplex != null) {
                                    ((ComplexElement) lastComplex).add(element);
                                }
                            } else if (type.isComplexElement())
                            {
                                if (lastComplex == null)
                                {
                            } else if (type.isComplexElement()) {
                                if (lastComplex == null) {
                                    lastComplex = element;
                                } else
                                {
                                } else {
                                    // @todo add process in here
                                    count++;
                                    lastComplex = element;
@@ -619,104 +548,23 @@
                            }
                        }
                    }
                } catch (IOException e)
                {
                } catch (IOException e) {
                    logger.warn("Stop read dgn file", e);
                } catch (Dgn7fileException e)
                {
                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                } finally
                {
                } catch (Dgn7fileException e) {
                    logger.warn(e.getMessage(), e);
                } finally {
                    reader.close();
                }
                System.out.println("count=" + count + " size=" + size);
                logger.debug("count=" + count + " size=" + size);
                // reader.close();
            } catch (IOException ioe)
            {
                System.out.println(ioe);
                ioe.printStackTrace();
            } catch (Dgn7fileException e)
            {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } catch (IOException ioe) {
                logger.warn(ioe.getMessage(), ioe);
            } catch (Dgn7fileException e) {
                logger.warn(e.getMessage(), e);
            }
        }
        System.exit(0);
    }
    public final class Record
    {
        int length;
        int number = 0;
        int offset;           // Relative to the whole file
        int start = 0;    // Relative to the current loaded buffer
        short signature = 0;
        /**
         * The minimum X value.
         */
        public double minX;
        /**
         * The minimum Y value.
         */
        public double minY;
        /**
         * The minimum Z value.
         */
        public double minZ;
        /**
         * The maximum X value.
         */
        public double maxX;
        /**
         * The maximum Y value.
         */
        public double maxY;
        /**
         * The maximum Z value.
         */
        public double maxZ;
        // ElementType type;
        int end = 0;    // Relative to the whole file
        Object element = null;
        IElementHandler handler;
        public Object element()
        {
            if (element == null)
            {
                buffer.position(start);
                buffer.order(ByteOrder.LITTLE_ENDIAN);
                if (handler == null)
                {
                    return null;
                }
                element = handler.read(buffer, signature, length);
            }
            return element;
        }
        public int offset()
        {
            return offset;
        }
        /**
         * A summary of the record.
         */
        public String toString()
        {
            return "Record " + number + " length " + length + " bounds " + minX + "," + minY + " " + maxX + "," + maxY;
        }
    }
}