/**
   * Parse a geometry starting at offset.
   *
   * @param data ValueGetter with the data to be parsed
   * @return the parsed geometry
   */
  protected Geometry parseGeometry(ValueGetter data) {
    byte endian = data.getByte(); // skip and test endian flag
    if (endian != data.endian) {
      throw new IllegalArgumentException("Endian inconsistency!");
    }
    int typeword = data.getInt();

    int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits

    boolean haveZ = (typeword & 0x80000000) != 0;
    boolean haveM = (typeword & 0x40000000) != 0;
    boolean haveS = (typeword & 0x20000000) != 0;

    int srid = Geometry.UNKNOWN_SRID;

    if (haveS) {
      srid = Geometry.parseSRID(data.getInt());
    }
    Geometry result1;
    switch (realtype) {
      case Geometry.POINT:
        result1 = parsePoint(data, haveZ, haveM);
        break;
      case Geometry.LINESTRING:
        result1 = parseLineString(data, haveZ, haveM);
        break;
      case Geometry.POLYGON:
        result1 = parsePolygon(data, haveZ, haveM);
        break;
      case Geometry.MULTIPOINT:
        result1 = parseMultiPoint(data);
        break;
      case Geometry.MULTILINESTRING:
        result1 = parseMultiLineString(data);
        break;
      case Geometry.MULTIPOLYGON:
        result1 = parseMultiPolygon(data);
        break;
      case Geometry.GEOMETRYCOLLECTION:
        result1 = parseCollection(data);
        break;
      default:
        throw new IllegalArgumentException("Unknown Geometry Type: " + realtype);
    }

    Geometry result = result1;

    if (srid != Geometry.UNKNOWN_SRID) {
      result.setSrid(srid);
    }
    return result;
  }