if (nBytes < recordLength) mShapeStream.skipBytes(recordLength - nBytes);
	public Row fetch() throws MapyrusException	{		int recordNumber;		int recordLength;		double x, y, lastX, lastY, xMin, yMin, xMax, yMax;		double fieldValue;		int i, shapeType;		int nBytes, nParts, nPoints, partIndex, pathIndex;		boolean shapeInExtents = false;		Row row;		double path[] = null;		try		{			/*			 * Keep reading until we get a shape inside the extents or we reach			 * the end of the file.			 */			row = new Row();			while (!shapeInExtents && mBytesRead < mShapeFileLength)			{				/*				 * Read header for next shape.  Convert record length to byte length.				 */				recordNumber = mShapeStream.readInt();				recordLength = mShapeStream.readInt() * 2;				shapeType = readLittleEndianInt(mShapeStream);				if (mShapeFileType == POINT)				{					/*					 * Read point coordinates, see if they are inside					 * query extents.					 */					path = new double[4];					path[0] = 4;					path[1] = PathIterator.SEG_MOVETO;										path[2] = readLittleEndianDouble(mShapeStream);					path[3] = readLittleEndianDouble(mShapeStream);					if (recordLength > 20)						mShapeStream.skip(recordLength - 20);					shapeInExtents = mQueryExtents.contains(path[2], path[3]);				}				else if (mShapeFileType == POLYLINE)				{					/*					 * Read bounding box of polyline.  Find if it intersects					 * with query extents.					 */					xMin = readLittleEndianDouble(mShapeStream);					yMin = readLittleEndianDouble(mShapeStream);					xMax = readLittleEndianDouble(mShapeStream);					yMax = readLittleEndianDouble(mShapeStream);					shapeInExtents = mQueryExtents.intersects(xMin, yMin, xMax - xMin, yMax - yMin);					if (shapeInExtents)					{						/*						 * Read polyline coordinates.						 */						nParts = readLittleEndianInt(mShapeStream);						nPoints = readLittleEndianInt(mShapeStream);						int []parts = new int[nParts];						for (i = 0; i < nParts; i++)							parts[i] = readLittleEndianInt(mShapeStream);						path = new double[nPoints * 3 + 1];						partIndex = 0;						pathIndex = 1;						lastX = lastY = Double.MAX_VALUE;						for (i = 0; i < nPoints; i++)						{							/*							 * Add next coordinates, as either a moveto or lineto.							 */							x = readLittleEndianDouble(mShapeStream);							y = readLittleEndianDouble(mShapeStream);							if (partIndex < nParts && parts[partIndex] == i)							{								path[pathIndex] = PathIterator.SEG_MOVETO;								partIndex++;							}							else if (x == lastX && y == lastY)							{								/*								 * Skip duplicate points.								 */								continue;							}							else							{								path[pathIndex] = PathIterator.SEG_LINETO;							}															path[pathIndex + 1] = lastX = x;							path[pathIndex + 2] = lastY = y;							pathIndex += 3;						}						path[0] = pathIndex;												/*						 * Skip any remaining bytes at end of record.						 */						nBytes = nPoints * 16 + nParts * 4 + 4 * 8 + 2 * 4 + 4;						if (nBytes < recordLength)							mShapeStream.skip(recordLength - nBytes);					}					else					{						/*						 * Line is outside query extents, skip it.						 */						mShapeStream.skip(recordLength - 4 * 8 - 4);					}				}				mBytesRead += recordLength + 8;				/*				 * Read attribute fields for this shape.  Don't bother				 * unpacking them if we are skipping this shape.				 */				mDBFStream.read(mDBFRecord);				while (mDBFRecord[0] == DBF_DELETED_RECORD)				{					/*					 * Skip deleted records.					 */					mDBFStream.read(mDBFRecord);				}				if (shapeInExtents)				{					int fieldIndex = 1;					for (i = 0; i < mShapeFieldTypes.length; i++)					{						Argument arg = null;						if (mShapeFieldTypes[i] == DBF_CHARACTER ||							mShapeFieldTypes[i] == DBF_DATE)						{							arg = new Argument(Argument.STRING,								unpackString(mDBFRecord, fieldIndex, mShapeFieldLengths[i]));						}						else if (mShapeFieldTypes[i] == DBF_NUMBER ||							mShapeFieldTypes[i] == DBF_FLOATING)						{							String s = unpackString(mDBFRecord,								fieldIndex, mShapeFieldLengths[i]);							try							{								fieldValue = Double.parseDouble(s);							}							catch (NumberFormatException e)							{								fieldValue = 0.0;							}							arg = new Argument(fieldValue);						}						else if (mShapeFieldTypes[i] == DBF_LOGICAL)						{							switch ((char)mDBFRecord[fieldIndex])							{								case 'y':								case 'Y':								case 'T':								case 't':									arg = new Argument(1.0);									break;								default:									arg = new Argument(0.0);									break;							}						}						row.add(arg);						fieldIndex += mShapeFieldLengths[i];					}										/*					 * Add geometry as final field.					 */					row.add(new Argument(path));				}			}		}		catch (IOException e)		{			throw new MapyrusException(e.getMessage());		}		/*		 * Return next row, or null if we did not find one.		 */		if (shapeInExtents)			return(row);		else			return(null);	}