View Javadoc
1 /* 2 * WKB4J - WKB reader for geographical mapping toolkits 3 * (C) 2002,2003, David Garnier, dgarnier@users.sourceforge.net 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation, 8 * version 2.1 of the License. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * or visit the web to http://www.gnu.org. 19 * 20 */ 21 22 package org.wkb4j.engine; 23 24 import java.io.DataInputStream; 25 import java.io.IOException; 26 27 import org.apache.log4j.Logger; 28 29 /*** 30 * Generate events from the submitted array of bytes holding binary data in the Well-Known Binary format. 31 * It generates a beginGeometry event when it sees the beginning of a given Geometry, 32 * an endGeometry event when it sees the end of a given Geometry, and an abortGeometry 33 * event if something happens that makes the completion of the current Geometry impossible. 34 * <br/>Points are treated differently from other Geometries: all the points in a Geometry are collected into a single 35 * array of byte and passed to the WKBFactory all at once. 36 * 37 * Events are nested, meaning that for a classical MultiLineString element with two LineStrings 38 * made of respectively 3 and 2 Points each, the following events will occur: 39 * 40 * <code> 41 * <ul> 42 * <li> beginWork()</li> 43 * <li> ...</li> 44 * <li> beginUnit() 45 * <ul> 46 * <li>beginMultiLineString(2) 47 * <ul> 48 * <li>beginLineString(3)</li> 49 * <li>addPoints(points)</li> 50 * <li>endLineString()</li> 51 * <li>beginLineString(2)</li> 52 * <li>addPoints(points)</li> 53 * <li>endLineString()</li> 54 * </ul> 55 * </li> 56 * <li>endMultiLineString()</li> 57 * </ul> 58 * <li> endUnit()</li> 59 * <li> ...</li> 60 * <li> endWork()</li> 61 * </ul> 62 * </code> 63 * <br/> 64 * 65 * The basic idea is to provide the author of each factory with as much freedom as possible while 66 * allowing for strong performance. 67 * 68 * wkbByteOrder aren't taken into account because will rely on the database to provide the data in the Big-Endian 69 * format (MSB, Most Significant Byte), the Endian used in Java. 70 * 71 * <br/>Inspired by the SAX API. 72 * 73 * <br/>Creation date: 6 juil. 2002 23:49:28 74 * @author David Garnier 75 * @version $Revision: 1.12 $ $Date: 2003/07/28 22:21:26 $ 76 */ 77 78 public class WKBParser implements WKBGeometryTypes { 79 protected static Logger log = Logger.getLogger(WKBParser.class); 80 81 protected WKBFactory factory = null; 82 83 public static final int DIMENSION2 = 2; 84 public static final int DIMENSION3 = 3; 85 86 /* This ResetableByteArrayInputStream is resetted each time getCoordinates is called, 87 so the initial value is not important.*/ 88 protected ResetableByteArrayInputStream internalBuffer = 89 new ResetableByteArrayInputStream(new byte[1]); 90 protected DataInputStream inputStream = new DataInputStream(internalBuffer); 91 92 protected String[] words; 93 94 protected final boolean endianess; 95 96 // private static int debugCounter = 0; 97 // private static int faultCounter = 0; 98 99 /*** 100 * Constructor for WKBParser. 101 * @param _factory that will receive the events. 102 */ 103 public WKBParser(WKBFactory _factory) { 104 factory = _factory; 105 words = new String[0]; 106 endianess = false; 107 } 108 109 /*** 110 * Constructor for WKBParser. 111 * @param _factory that will receive the events. 112 */ 113 public WKBParser( 114 WKBFactory _factory, 115 String[] _words, 116 boolean _endianess) { 117 factory = _factory; 118 words = _words; 119 endianess = _endianess; 120 } 121 122 /*** 123 * Load the raw bytes in the WKB format representing one record of the DB and generates the events. 124 * 125 * The <code>sridBuffer<code> should contain an array of bytes holding the SRID of the current geometry. 126 * If sridBuffer is null or longer than 4 bytes, the SRID of the current geometry is set to -1 127 * @param buffer array of bytes holding the data in the WKB format 128 * @param sridBuffer . 129 * @parem _endianess Endianess of the sridBuffer, the main buffer should always be BigEndian. True is BigEndian, False is LittleEndian 130 * */ 131 public void parseData(byte[] buffer, byte[] sridBuffer) 132 throws IOException { 133 int srid = parseInt(sridBuffer, endianess); 134 parseData(buffer, srid); 135 } 136 137 protected int parseInt(byte[] intBuffer, boolean endianess) 138 throws IOException { 139 int srid = -2; 140 if (intBuffer != null && intBuffer.length == 4) { 141 if (endianess) { 142 srid = 143 (intBuffer[0]) 144 << 24 | (intBuffer[1] & 0xff) 145 << 16 | (intBuffer[2] & 0xff) 146 << 8 | (intBuffer[3] & 0xff); 147 } else { 148 srid = 149 (intBuffer[3]) 150 << 24 | (intBuffer[2] & 0xff) 151 << 16 | (intBuffer[1] & 0xff) 152 << 8 | (intBuffer[0] & 0xff); 153 } 154 } 155 return srid; 156 } 157 158 /*** 159 * Load the raw bytes in the WKB format and generates the events. 160 * @param buffer array of bytes holding the data in the WKB format 161 * @param srid The SRID of the current geometry. 162 * */ 163 public void parseData(byte[] buffer, byte[][] datas) throws IOException { 164 165 // if (words.length != datas.length) { 166 // log.error( 167 // "Words and datas have different size. Emptying everything"); 168 // words = new String[0]; 169 // datas = new byte[0][0]; 170 // } 171 int[] values = new int[words.length]; 172 for (int i = 0; i < values.length; i++) { 173 values[i] = parseInt(datas[i], endianess); 174 // log.debug(""+ values[i]); 175 } 176 getInternalBuffer().reset(buffer); 177 getInputStream().reset(); 178 decodeData(words, values); 179 } 180 181 /*** 182 * Load the raw bytes in the WKB format and generates the events. 183 * @param buffer array of bytes holding the data in the WKB format 184 * @param srid The SRID of the current geometry. 185 * */ 186 public void parseData(byte[] buffer, int srid) throws IOException { 187 // if (log.isDebugEnabled()) { 188 // log.debug("" + srid); 189 // } 190 getInternalBuffer().reset(buffer); 191 getInputStream().reset(); 192 decodeData(new String[] { "srid" }, new int[] { srid }); 193 } 194 195 /*** 196 * Returns the ResetableByteArrayInputStream 197 * @return ResetableByteArrayInputStream 198 */ 199 private ResetableByteArrayInputStream getInternalBuffer() { 200 return internalBuffer; 201 } 202 203 /*** 204 * Sets the ResetableByteArrayInputStream 205 * @param internalBuffer The ResetableByteArrayInputStream to set 206 */ 207 private void setInternalBuffer(ResetableByteArrayInputStream internalBuffer) { 208 this.internalBuffer = internalBuffer; 209 } 210 211 /*** 212 * Returns the DataInputStream used to transform bytes into native types (<code>int</code> and <code>double</code> in our case). 213 * @return DataInputStream 214 */ 215 private DataInputStream getInputStream() { 216 return inputStream; 217 } 218 219 /*** 220 * Sets the DataInputStream used to transform bytes into native types (<code>int</code> and <code>double</code> in our case). 221 . 222 * @param inputStream The inputStream to set 223 */ 224 // private void setInputStream(DataInputStream inputStream) { 225 // this.inputStream = inputStream; 226 // } 227 228 /*** Read the raw WKB data from the DataInputStream and generate the beginUnit/endUnit calls and 229 * the calls to the top-level geometries (<code>MultiLineString, LineString, Polygon, MultiPolygon, 230 * GeometryCollection, Point<code>)<br/> All the readGeometry method can throw IOException if something goes wrong. 231 * @param srid defines the SRID applied to all the geometries contained in the current record. 232 * 233 * */ 234 protected void decodeData(String[] words, int[] values) { 235 /* Right now if something goes wrong we just abort the curren unit and continue with the next record.*/ 236 try { 237 238 /* Against our best code, the result is encoded as little, so it must be reversed.*/ 239 if (inputStream.readByte() == 1) { 240 241 } 242 //read the wkbType() 243 int geotype = inputStream.readInt(); 244 if (geotype > 1000) { 245 log.debug("Geotype:" + geotype); 246 } 247 factory.beginUnit(words, values); 248 parseType(geotype, DIMENSION2); 249 factory.endUnit(); 250 } catch (IOException ioe) { 251 log.error("Problem is the current record:\n", ioe); 252 factory.abortUnit(); 253 } 254 } 255 256 /*** 257 * Read the given and generates the corresponding events. Do not call beginUnit(); nor endUnit(): 258 * @param geotype type of the next Geometry. 259 * @param dimension dimension of the points contained in the next geometry. 260 * @throws IOException 261 */ 262 protected boolean parseType(final int geotype, final int dimension) 263 throws IOException { 264 // if (debugCounter % 10000 == 0) { 265 // log.info("Debug counter: " + debugCounter); 266 // //readAll(); 267 // // return true; 268 // } 269 // 270 // debugCounter++; 271 272 switch (geotype) { 273 case (wkbMultiLineString) : 274 readMultiLineString(); 275 break; 276 case (wkbLineString) : 277 readLineString(dimension); 278 break; 279 case (wkbPolygon) : 280 readPolygon(dimension); 281 break; 282 case (wkbMultiPolygon) : 283 readMultiPolygon(dimension); 284 break; 285 case (wkbPoint) : 286 readPoint(dimension); 287 break; 288 case (wkbMultiPoint) : 289 readMultiPoint(); 290 break; 291 case (wkbGeometryCollection) : 292 readGeometryCollection(); 293 break; 294 default : 295 log.error( 296 "The current buffer of bytes doesn't start with a valid GeometryType but with: " 297 + geotype 298 + "\n Moving to the next record as a result."); 299 } 300 return true; 301 } 302 303 /*** 304 * Reads a MultiLineString. 305 * @throws IOException 306 */ 307 protected void readMultiLineString() throws IOException { 308 int size = inputStream.readInt(); 309 factory.beginMultiLineString(size); 310 for (int i = 0; i < size; i++) { 311 //skip the byteOrder byte 312 inputStream.skipBytes(1); 313 int tmp = inputStream.readInt(); 314 if (tmp != wkbLineString) { 315 factory.abortMultiLineString(); 316 return; 317 } 318 readLineString(DIMENSION2); 319 } 320 factory.endMultiLineString(); 321 } 322 323 /*** 324 * Reads a LineString. 325 * @param dimension dimension of the points contained in this geometry. 326 * @throws IOException 327 */ 328 protected void readLineString(final int dimension) throws IOException { 329 int size = inputStream.readInt(); 330 factory.beginLineString(size); 331 readPoints(size, dimension); 332 factory.endLineString(); 333 } 334 335 /*** 336 * Reads a number of Points. 337 * @param pointCount 338 * @param dimension unused parameter 339 * @throws IOException 340 */ 341 protected void readPoints(int pointCount, int dimension) 342 throws IOException { 343 pointCount <<= 1; 344 double[] sendVal = new double[pointCount]; 345 for (int i = 0; i < pointCount; i++) { 346 sendVal[i] = (float) inputStream.readDouble(); 347 } 348 factory.addPoints(sendVal); 349 } 350 351 /*** 352 * Reads a MultiPolygon. 353 * @param dimension dimension of the points contained in this geometry. 354 * @throws IOException 355 */ 356 protected void readMultiPolygon(int dimension) throws IOException { 357 int size = inputStream.readInt(); 358 factory.beginMultiPolygon(size); 359 for (int i = 0; i < size; i++) { 360 //skip the byteOrder byte 361 inputStream.skipBytes(1); 362 if (inputStream.readInt() != wkbPolygon) { 363 factory.abortMultiPolygon(); 364 return; 365 } 366 readPolygon(DIMENSION2); 367 } 368 factory.endMultiPolygon(); 369 } 370 371 /*** 372 * Reads a Polygon. 373 * @param dimension dimension of the points contained in this geometry. 374 * @throws IOException 375 */ 376 protected void readPolygon(int dimension) throws IOException { 377 int size = inputStream.readInt(); 378 factory.beginPolygon(size); 379 for (int i = 0; i < size; i++) { 380 readLinearRing(dimension); 381 } 382 factory.endPolygon(); 383 } 384 385 /*** 386 * Method readLinearRing. 387 * @param dimension dimension of the points contained in this geometry. 388 * @throws IOException 389 */ 390 protected void readLinearRing(int dimension) throws IOException { 391 int size = inputStream.readInt(); 392 factory.beginLinearRing(size); 393 readPoints(size, dimension); 394 factory.endLinearRing(); 395 } 396 397 /*** 398 * Reads a MultiPoint. 399 * @throws IOException 400 */ 401 /* An optimization of this method is possible. 402 * Right now it just call readPoint repetively, which is correct because a MultiPoint 403 * is made of Points. However, it is possible to reduce overhead by reading the coordinates directly. 404 * All factories would have to be modified.*/ 405 protected void readMultiPoint() throws IOException { 406 int size = inputStream.readInt(); 407 factory.beginMultiPoint(size); 408 for (int i = 0; i < size; i++) { 409 //skip the byteOrder byte 410 inputStream.skipBytes(1); 411 if (inputStream.readInt() != wkbPoint) { 412 factory.abortMultiPoint(); 413 return; 414 } 415 readPoint(DIMENSION2); 416 } 417 factory.endMultiPoint(); 418 } 419 420 /*** 421 * Reads a GeometryCollection. 422 * @param dimension dimension of the points contained in this geometry. 423 * @throws IOException 424 */ 425 protected void readGeometryCollection() throws IOException { 426 int size = inputStream.readInt(); 427 factory.beginGeometryCollection(size); 428 for (int i = 0; i < size; i++) { 429 //skip the byteOrder byte 430 inputStream.skipBytes(1); 431 if (!parseType(inputStream.readInt(), DIMENSION2)) { 432 factory.abortGeometryCollection(); 433 return; 434 } 435 factory.newGeometryCollectionComponent(); 436 } 437 factory.endGeometryCollection(); 438 } 439 440 /*** 441 * Reads a Point. 442 * @param dimension dimension of the points contained in this geometry. 443 * @throws IOException 444 */ 445 protected void readPoint(int dimension) throws IOException { 446 factory.beginPoint(); 447 readPoints(1, dimension); 448 factory.endPoint(); 449 } 450 451 // /*** 452 // * Reads a GeometryCollection. 453 // * @param dimension dimension of the points contained in this geometry. 454 // * @throws IOException 455 // */ 456 // protected void readAll() throws IOException { 457 // for (int i = 0; i < 6; i++) { 458 // try { 459 // 460 // System.out.print(inputStream.readInt() + ":"); 461 // } catch (Exception e) { 462 // // System.exit(0); 463 // } 464 // } 465 // System.out.print("\n"); 466 // } 467 }

This page was automatically generated by Maven