EVOLUTION-MANAGER
Edit File: WKBReader.cpp
/********************************************************************** * * GEOS - Geometry Engine Open Source * http://geos.osgeo.org * * Copyright (C) 2005-2006 Refractions Research Inc. * * This is free software; you can redistribute and/or modify it under * the terms of the GNU Lesser General Public Licence as published * by the Free Software Foundation. * See the COPYING file for more information. * ********************************************************************** * * Last port: io/WKBReader.java rev. 1.1 (JTS-1.7) * **********************************************************************/ #include <geos/io/WKBReader.h> #include <geos/io/WKBConstants.h> #include <geos/io/ByteOrderValues.h> #include <geos/io/ParseException.h> #include <geos/geom/GeometryFactory.h> #include <geos/geom/Coordinate.h> #include <geos/geom/Point.h> #include <geos/geom/LinearRing.h> #include <geos/geom/LineString.h> #include <geos/geom/Polygon.h> #include <geos/geom/MultiPoint.h> #include <geos/geom/MultiLineString.h> #include <geos/geom/MultiPolygon.h> #include <geos/geom/CoordinateSequenceFactory.h> #include <geos/geom/CoordinateSequence.h> #include <geos/geom/PrecisionModel.h> #include <iomanip> #include <ostream> #include <sstream> #include <string> //#define DEBUG_WKB_READER 1 using namespace std; using namespace geos::geom; namespace geos { namespace io { // geos.io WKBReader::WKBReader() : factory(*(GeometryFactory::getDefaultInstance())) {} ostream& WKBReader::printHEX(istream& is, ostream& os) { static const char hex[] = "0123456789ABCDEF"; std::streampos pos = is.tellg(); // take note of input stream get pointer is.seekg(0, ios::beg); // rewind input stream char each = 0; while(is.read(&each, 1)) { const unsigned char c = each; int low = (c & 0x0F); int high = (c >> 4); os << hex[high] << hex[low]; } is.clear(); // clear input stream eof flag is.seekg(pos); // reset input stream position return os; } namespace { unsigned char ASCIIHexToUChar(char val) { switch(val) { case '0' : return 0; case '1' : return 1; case '2' : return 2; case '3' : return 3; case '4' : return 4; case '5' : return 5; case '6' : return 6; case '7' : return 7; case '8' : return 8; case '9' : return 9; case 'A' : case 'a' : return 10; case 'B' : case 'b' : return 11; case 'C' : case 'c' : return 12; case 'D' : case 'd' : return 13; case 'E' : case 'e' : return 14; case 'F' : case 'f' : return 15; default: throw ParseException("Invalid HEX char"); } } } // namespace // Must be an even number of characters in the istream. // Throws a ParseException if there are an odd number of characters. std::unique_ptr<Geometry> WKBReader::readHEX(istream& is) { // setup input/output stream stringstream os(ios_base::binary | ios_base::in | ios_base::out); while(true) { const int input_high = is.get(); if(input_high == char_traits<char>::eof()) { break; } const int input_low = is.get(); if(input_low == char_traits<char>::eof()) { throw ParseException("Premature end of HEX string"); } const char high = static_cast<char>(input_high); const char low = static_cast<char>(input_low); const unsigned char result_high = ASCIIHexToUChar(high); const unsigned char result_low = ASCIIHexToUChar(low); const unsigned char value = static_cast<char>((result_high << 4) + result_low); #if DEBUG_HEX_READER cout << "HEX " << high << low << " -> DEC " << (int)value << endl; #endif // write the value to the output stream os << value; } // now call read to convert the geometry return this->read(os); } std::unique_ptr<Geometry> WKBReader::read(istream& is) { dis.setInStream(&is); // will default to machine endian return readGeometry(); } std::unique_ptr<Geometry> WKBReader::readGeometry() { // determine byte order unsigned char byteOrder = dis.readByte(); #if DEBUG_WKB_READER cout << "WKB byteOrder: " << (int)byteOrder << endl; #endif // default is machine endian if(byteOrder == WKBConstants::wkbNDR) { dis.setOrder(ByteOrderValues::ENDIAN_LITTLE); } else if(byteOrder == WKBConstants::wkbXDR) { dis.setOrder(ByteOrderValues::ENDIAN_BIG); } int typeInt = dis.readInt(); /* Pick up both ISO and SFSQL geometry type */ int geometryType = (typeInt & 0xffff) % 1000; /* ISO type range 1000 is Z, 2000 is M, 3000 is ZM */ int isoTypeRange = (typeInt & 0xffff) / 1000; int isoHasZ = (isoTypeRange == 1) || (isoTypeRange == 3); //int isoHasM = (isoTypeRange == 2) || (isoTypeRange == 3); /* SFSQL high bit flag for Z, next bit for M */ int sfsqlHasZ = (typeInt & 0x80000000) != 0; //int sfsqlHasM = (typeInt & 0x40000000) != 0; #if DEBUG_WKB_READER cout << "WKB geometryType: " << geometryType << endl; #endif bool hasZ = sfsqlHasZ || isoHasZ; if(hasZ) { inputDimension = 3; } else { inputDimension = 2; // doesn't handle M currently } #if DEBUG_WKB_READER cout << "WKB hasZ: " << hasZ << endl; #endif #if DEBUG_WKB_READER cout << "WKB dimensions: " << inputDimension << endl; #endif bool hasSRID = ((typeInt & 0x20000000) != 0); #if DEBUG_WKB_READER cout << "WKB hasSRID: " << hasSRID << endl; #endif int SRID = 0; if(hasSRID) { SRID = dis.readInt(); // read SRID } // allocate space for ordValues if(ordValues.size() < inputDimension) { ordValues.resize(inputDimension); } std::unique_ptr<Geometry> result; switch(geometryType) { case WKBConstants::wkbPoint : result = readPoint(); break; case WKBConstants::wkbLineString : result = readLineString(); break; case WKBConstants::wkbPolygon : result = readPolygon(); break; case WKBConstants::wkbMultiPoint : result = readMultiPoint(); break; case WKBConstants::wkbMultiLineString : result = readMultiLineString(); break; case WKBConstants::wkbMultiPolygon : result = readMultiPolygon(); break; case WKBConstants::wkbGeometryCollection : result = readGeometryCollection(); break; default: stringstream err; err << "Unknown WKB type " << geometryType; throw ParseException(err.str()); } result->setSRID(SRID); return result; } std::unique_ptr<Point> WKBReader::readPoint() { readCoordinate(); if(inputDimension == 3) { return std::unique_ptr<Point>(factory.createPoint(Coordinate(ordValues[0], ordValues[1], ordValues[2]))); } else { return std::unique_ptr<Point>(factory.createPoint(Coordinate(ordValues[0], ordValues[1]))); } } std::unique_ptr<LineString> WKBReader::readLineString() { int size = dis.readInt(); #if DEBUG_WKB_READER cout << "WKB npoints: " << size << endl; #endif auto pts = readCoordinateSequence(size); return factory.createLineString(std::move(pts)); } std::unique_ptr<LinearRing> WKBReader::readLinearRing() { int size = dis.readInt(); #if DEBUG_WKB_READER cout << "WKB npoints: " << size << endl; #endif auto pts = readCoordinateSequence(size); return factory.createLinearRing(std::move(pts)); } std::unique_ptr<Polygon> WKBReader::readPolygon() { int numRings = dis.readInt(); #if DEBUG_WKB_READER cout << "WKB numRings: " << numRings << endl; #endif std::unique_ptr<LinearRing> shell; if(numRings > 0) { shell = readLinearRing(); } if(numRings > 1) { std::vector<std::unique_ptr<LinearRing>> holes(numRings - 1); for(int i = 0; i < numRings - 1; i++) { holes[i] = readLinearRing(); } return factory.createPolygon(std::move(shell), std::move(holes)); } return factory.createPolygon(std::move(shell)); } std::unique_ptr<MultiPoint> WKBReader::readMultiPoint() { int numGeoms = dis.readInt(); std::vector<std::unique_ptr<Geometry>> geoms(numGeoms); for(int i = 0; i < numGeoms; i++) { geoms[i] = readGeometry(); if(!dynamic_cast<Point*>(geoms[i].get())) { stringstream err; err << BAD_GEOM_TYPE_MSG << " MultiPoint"; throw ParseException(err.str()); } } return factory.createMultiPoint(std::move(geoms)); } std::unique_ptr<MultiLineString> WKBReader::readMultiLineString() { int numGeoms = dis.readInt(); std::vector<std::unique_ptr<Geometry>> geoms(numGeoms); for(int i = 0; i < numGeoms; i++) { geoms[i] = readGeometry(); if(!dynamic_cast<LineString*>(geoms[i].get())) { stringstream err; err << BAD_GEOM_TYPE_MSG << " LineString"; throw ParseException(err.str()); } } return factory.createMultiLineString(std::move(geoms)); } std::unique_ptr<MultiPolygon> WKBReader::readMultiPolygon() { int numGeoms = dis.readInt(); std::vector<std::unique_ptr<Geometry>> geoms(numGeoms); for(int i = 0; i < numGeoms; i++) { geoms[i] = readGeometry(); if(!dynamic_cast<Polygon*>(geoms[i].get())) { stringstream err; err << BAD_GEOM_TYPE_MSG << " Polygon"; throw ParseException(err.str()); } } return factory.createMultiPolygon(std::move(geoms)); } std::unique_ptr<GeometryCollection> WKBReader::readGeometryCollection() { int numGeoms = dis.readInt(); std::vector<std::unique_ptr<Geometry>> geoms(numGeoms); for(int i = 0; i < numGeoms; i++) { geoms[i] = readGeometry(); } return factory.createGeometryCollection(std::move(geoms)); } std::unique_ptr<CoordinateSequence> WKBReader::readCoordinateSequence(int size) { auto seq = factory.getCoordinateSequenceFactory()->create(size, inputDimension); auto targetDim = seq->getDimension(); if(targetDim > inputDimension) { targetDim = inputDimension; } for(int i = 0; i < size; i++) { readCoordinate(); for(unsigned int j = 0; j < targetDim; j++) { seq->setOrdinate(i, j, ordValues[j]); } } return seq; } void WKBReader::readCoordinate() { const PrecisionModel& pm = *factory.getPrecisionModel(); for(unsigned int i = 0; i < inputDimension; ++i) { if(i <= 1) { ordValues[i] = pm.makePrecise(dis.readDouble()); } else { ordValues[i] = dis.readDouble(); } } #if DEBUG_WKB_READER cout << "WKB coordinate: " << ordValues[0] << "," << ordValues[1] << endl; #endif } } // namespace geos.io } // namespace geos