| // SPDX-License-Identifier: LGPL-2.1-or-later |
| // Copyright (c) 2012-2014 Monty Program Ab |
| // Copyright (c) 2015-2021 MariaDB Corporation Ab |
| |
| package org.mariadb.jdbc.type; |
| |
| import java.sql.SQLDataException; |
| import org.mariadb.jdbc.client.Column; |
| import org.mariadb.jdbc.client.ReadableByteBuf; |
| |
| /** Geometry parser */ |
| public interface Geometry { |
| |
| /** |
| * Parse point from packet |
| * |
| * @param littleEndian encoding order |
| * @param buf packet buffer |
| * @return point value |
| */ |
| static Point parsePoint(boolean littleEndian, ReadableByteBuf buf) { |
| double x = littleEndian ? buf.readDouble() : buf.readDoubleBE(); |
| double y = littleEndian ? buf.readDouble() : buf.readDoubleBE(); |
| return new Point(x, y); |
| } |
| |
| /** |
| * parse geometry object |
| * |
| * @param buf packet buffer |
| * @param length data length |
| * @param column column meta |
| * @return geometry parsed object |
| * @throws SQLDataException if parsing exception occurs |
| */ |
| static Geometry getGeometry(ReadableByteBuf buf, int length, Column column) |
| throws SQLDataException { |
| if (length == 0) return null; |
| boolean littleEndian = buf.readByte() == 0x01; |
| int dataType = littleEndian ? buf.readInt() : buf.readIntBE(); |
| switch (dataType) { |
| case 1: |
| // wkbPoint |
| return parsePoint(littleEndian, buf); |
| |
| case 2: |
| // wkbLineString |
| int pointNumber = littleEndian ? buf.readInt() : buf.readIntBE(); |
| Point[] points = new Point[pointNumber]; |
| for (int i = 0; i < pointNumber; i++) { |
| points[i] = parsePoint(littleEndian, buf); |
| } |
| return new LineString(points, true); |
| |
| case 3: |
| // wkbPolygon |
| int numRings = littleEndian ? buf.readInt() : buf.readIntBE(); |
| LineString[] lines = new LineString[numRings]; |
| for (int i = 0; i < numRings; i++) { |
| int pointNb = littleEndian ? buf.readInt() : buf.readIntBE(); |
| Point[] lsPoints = new Point[pointNb]; |
| for (int j = 0; j < pointNb; j++) { |
| lsPoints[j] = parsePoint(littleEndian, buf); |
| } |
| lines[i] = new LineString(lsPoints, false); |
| } |
| return new Polygon(lines); |
| |
| case 4: |
| // wkbMultiPoint |
| int pointNb = littleEndian ? buf.readInt() : buf.readIntBE(); |
| Point[] pointArr = new Point[pointNb]; |
| for (int i = 0; i < pointNb; i++) { |
| pointArr[i] = (Point) getGeometry(buf, length, column); |
| } |
| return new MultiPoint(pointArr); |
| |
| case 5: |
| // wkbMultiLinestring |
| int multiNb = littleEndian ? buf.readInt() : buf.readIntBE(); |
| LineString[] multiLines = new LineString[multiNb]; |
| for (int i = 0; i < multiNb; i++) { |
| multiLines[i] = (LineString) getGeometry(buf, length, column); |
| } |
| return new MultiLineString(multiLines); |
| |
| case 6: |
| // wkbMultiPolygon |
| int multiPolyNb = littleEndian ? buf.readInt() : buf.readIntBE(); |
| Polygon[] multiPolygons = new Polygon[multiPolyNb]; |
| for (int i = 0; i < multiPolyNb; i++) { |
| multiPolygons[i] = (Polygon) getGeometry(buf, length, column); |
| } |
| return new MultiPolygon(multiPolygons); |
| |
| case 7: |
| // wkbGeometryCollection |
| int multiCollNb = littleEndian ? buf.readInt() : buf.readIntBE(); |
| Geometry[] multiGeos = new Geometry[multiCollNb]; |
| for (int i = 0; i < multiCollNb; i++) { |
| multiGeos[i] = getGeometry(buf, length, column); |
| } |
| return new GeometryCollection(multiGeos); |
| |
| default: |
| // ERROR |
| buf.skip(length - 5); |
| throw new SQLDataException( |
| String.format("Data type %s cannot be decoded as Geometry", column.getType())); |
| } |
| } |
| } |