/** * Transfer (by bytes) the data at the current record to the ShapefileWriter. * * @param bounds double array of length four for transfering the bounds into * @return The length of the record transfered in bytes */ public int transferTo(ShapefileWriter writer, int recordNum, double[] bounds) throws IOException { buffer.position(this.toBufferOffset(record.end)); buffer.order(ByteOrder.BIG_ENDIAN); buffer.getInt(); // record number int rl = buffer.getInt(); int mark = buffer.position(); int len = rl * 2; buffer.order(ByteOrder.LITTLE_ENDIAN); ShapeType recordType = ShapeType.forID(buffer.getInt()); if (recordType.isMultiPoint()) { for (int i = 0; i < 4; i++) { bounds[i] = buffer.getDouble(); } } else if (recordType != ShapeType.NULL) { bounds[0] = bounds[1] = buffer.getDouble(); bounds[2] = bounds[3] = buffer.getDouble(); } // write header to shp and shx headerTransfer.position(0); headerTransfer.putInt(recordNum).putInt(rl).position(0); writer.shpChannel.write(headerTransfer); headerTransfer.putInt(0, writer.offset).position(0); writer.offset += rl + 4; writer.shxChannel.write(headerTransfer); // reset to mark and limit at end of record, then write int oldLimit = buffer.limit(); buffer.position(mark).limit(mark + len); writer.shpChannel.write(buffer); buffer.limit(oldLimit); record.end = this.toFileOffset(buffer.position()); record.number++; return len; }
/** * Fetch the next record information. * * @param offset * @throws IOException * @return The record instance associated with this reader. */ public Geometry geomAt(int offset) throws IOException { // need to update position buffer.position(offset); // record header buffer.skip(8); // shape record is all little endian buffer.order(ByteOrder.LITTLE_ENDIAN); // read the type, handlers don't need it ShapeType recordType = ShapeType.forID(buffer.getInt()); // this usually happens if the handler logic is bunk, // but bad files could exist as well... if (recordType != ShapeType.NULL && recordType != fileShapeType) { throw new IllegalStateException( "ShapeType changed illegally from " + fileShapeType + " to " + recordType); } return handler.read(buffer, recordType); }
/** * Fetch the next record information. * * @throws IOException * @return The record instance associated with this reader. */ public Record nextRecord() throws IOException { // need to update position buffer.position(getNextOffset()); if (currentShape != UNKNOWN) currentShape++; // record header is big endian buffer.order(ByteOrder.BIG_ENDIAN); // read shape record header int recordNumber = buffer.getInt(); // silly ESRI say contentLength is in 2-byte words // and ByteByffer uses bytes. // track the record location int recordLength = buffer.getInt() * 2; if (!buffer.isReadOnly() && !useMemoryMappedBuffer) { // capacity is less than required for the record // copy the old into the newly allocated if (buffer.capacity() < recordLength + 8) { this.currentOffset += buffer.position(); ByteBuffer old = buffer; // ensure enough capacity for one more record header buffer = ensureCapacity(buffer, recordLength + 8, useMemoryMappedBuffer); buffer.put(old); NIOUtilities.clean(old, useMemoryMappedBuffer); fill(buffer, channel); buffer.position(0); } else // remaining is less than record length // compact the remaining data and read again, // allowing enough room for one more record header if (buffer.remaining() < recordLength + 8) { this.currentOffset += buffer.position(); buffer.compact(); fill(buffer, channel); buffer.position(0); } } // shape record is all little endian buffer.order(ByteOrder.LITTLE_ENDIAN); // read the type, handlers don't need it ShapeType recordType = ShapeType.forID(buffer.getInt()); // this usually happens if the handler logic is bunk, // but bad files could exist as well... if (recordType != ShapeType.NULL && recordType != fileShapeType) { throw new IllegalStateException( "ShapeType changed illegally from " + fileShapeType + " to " + recordType); } // peek at bounds, then reset for handler // many handler's may ignore bounds reading, but we don't want to // second guess them... buffer.mark(); if (recordType.isMultiPoint()) { record.minX = buffer.getDouble(); record.minY = buffer.getDouble(); record.maxX = buffer.getDouble(); record.maxY = buffer.getDouble(); } else if (recordType != ShapeType.NULL) { record.minX = record.maxX = buffer.getDouble(); record.minY = record.maxY = buffer.getDouble(); } buffer.reset(); record.offset = record.end; // update all the record info. record.length = recordLength; record.type = recordType; record.number = recordNumber; // remember, we read one int already... record.end = this.toFileOffset(buffer.position()) + recordLength - 4; // mark this position for the reader record.start = buffer.position(); // clear any cached shape record.shape = null; return record; }