Changeset 34820 in osm for applications/editors/josm/plugins/o5m/src
- Timestamp:
- 2019-01-13T14:19:42+01:00 (6 years ago)
- Location:
- applications/editors/josm/plugins/o5m/src/org/openstreetmap/josm/plugins/o5m
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/o5m/src/org/openstreetmap/josm/plugins/o5m/O5mConstants.java
r33012 r34820 7 7 8 8 /** 9 * 9 * Constants for o5m plugin. 10 10 * @author GerdP 11 11 * -
applications/editors/josm/plugins/o5m/src/org/openstreetmap/josm/plugins/o5m/O5mPlugin.java
r33012 r34820 9 9 /** 10 10 * 11 * o5m Plugin 11 12 * @author GerdP 12 13 * -
applications/editors/josm/plugins/o5m/src/org/openstreetmap/josm/plugins/o5m/io/O5mImporter.java
r33566 r34820 14 14 15 15 /** 16 * OSM Importer for o5m format (*.o5m). 16 17 * @author GerdP 17 18 * -
applications/editors/josm/plugins/o5m/src/org/openstreetmap/josm/plugins/o5m/io/O5mReader.java
r34599 r34820 29 29 import org.openstreetmap.josm.io.AbstractReader; 30 30 import org.openstreetmap.josm.io.IllegalDataException; 31 import org.openstreetmap.josm.io.ImportCancelException; 31 32 import org.openstreetmap.josm.tools.CheckParameterUtil; 32 33 import org.openstreetmap.josm.tools.Logging; 33 34 34 35 /** 36 * Read stream in o5m format. 35 37 * @author GerdP 36 38 * … … 58 60 } 59 61 60 // O5M data set constants 61 private static final int NODE_DATASET = 0x10; 62 private static final int WAY_DATASET = 0x11; 63 private static final int REL_DATASET = 0x12; 64 private static final int BBOX_DATASET = 0xdb; 65 private static final int TIMESTAMP_DATASET = 0xdc; 66 private static final int HEADER_DATASET = 0xe0; 67 private static final int EOD_FLAG = 0xfe; 68 private static final int RESET_FLAG = 0xff; 69 70 private static final int EOF_FLAG = -1; 71 72 // o5m constants 73 private static final int STRING_TABLE_SIZE = 15000; 74 private static final int MAX_STRING_PAIR_SIZE = 250 + 2; 75 private static final String[] REL_REF_TYPES = {"node", "way", "relation", "?"}; 76 private static final double FACTOR = 1d/1000000000; // used with 100*<Val>*FACTOR 77 78 private final BufferedInputStream fis; 79 private InputStream is; 80 private ByteArrayInputStream bis; 81 82 // buffer for byte -> String conversions 83 private byte[] cnvBuffer; 84 85 private byte[] ioBuf; 86 private int ioPos; 87 // the o5m string table 88 private String[][] stringTable; 89 private String[] stringPair; 90 private int currStringTablePos; 91 // a counter that must be maintained by all routines that read data from the stream 92 private int bytesToRead; 93 // total number of bytes read from stream 94 long countBytes; 95 96 // for delta calculations 97 private long lastNodeId; 98 private long lastWayId; 99 private long lastRelId; 100 private long[] lastRef; 101 private long lastTs; 102 private long lastChangeSet; 103 private int lastLon, lastLat; 104 private int version; 105 private User osmUser; 106 private String header; 107 /** 108 * A parser for the o5m format 109 * @param stream The InputStream that contains the OSM data in o5m format 110 */ 111 O5mReader(InputStream stream) { 112 this.fis = new BufferedInputStream(stream); 62 // O5M data set constants 63 private static final int NODE_DATASET = 0x10; 64 private static final int WAY_DATASET = 0x11; 65 private static final int REL_DATASET = 0x12; 66 private static final int BBOX_DATASET = 0xdb; 67 private static final int TIMESTAMP_DATASET = 0xdc; 68 private static final int HEADER_DATASET = 0xe0; 69 private static final int EOD_FLAG = 0xfe; 70 private static final int RESET_FLAG = 0xff; 71 72 private static final int EOF_FLAG = -1; 73 74 // o5m constants 75 private static final int STRING_TABLE_SIZE = 15000; 76 private static final int MAX_STRING_PAIR_SIZE = 250 + 2; 77 private static final String[] REL_REF_TYPES = {"node", "way", "relation", "?"}; 78 private static final double FACTOR = 1d/1000000000; // used with 100*<Val>*FACTOR 79 80 private BufferedInputStream fis; 81 private InputStream is; 82 private ByteArrayInputStream bis; 83 84 // buffer for byte -> String conversions 85 private byte[] cnvBuffer; 86 87 private byte[] ioBuf; 88 private int ioPos; 89 // the o5m string table 90 private String[][] stringTable; 91 private String[] stringPair; 92 private int currStringTablePos; 93 // a counter that must be maintained by all routines that read data from the stream 94 private int bytesToRead; 95 // total number of bytes read from stream 96 long countBytes; 97 98 // for delta calculations 99 private long lastNodeId; 100 private long lastWayId; 101 private long lastRelId; 102 private long[] lastRef; 103 private long lastTs; 104 private long lastChangeSet; 105 private int lastLon, lastLat; 106 private int version; 107 private User osmUser; 108 private String header; 109 /** 110 * A parser for the o5m format 111 */ 112 O5mReader() { 113 this.cnvBuffer = new byte[4000]; // OSM data should not contain string pairs with length > 512 114 this.ioBuf = new byte[8192]; 115 this.ioPos = 0; 116 this.stringPair = new String[2]; 117 this.lastRef = new long[3]; 118 reset(); 119 } 120 121 /** 122 * parse the input stream 123 * @param source The InputStream that contains the OSM data in o5m format 124 * @throws O5mParsingCancelException if operation was canceled 125 */ 126 public void parse(InputStream source) throws O5mParsingCancelException { 127 this.fis = new BufferedInputStream(source); 128 is = fis; 129 130 try { 131 int start = is.read(); 132 ++countBytes; 133 if (start != RESET_FLAG) 134 throw new IOException(tr("wrong header byte ") + Integer.toHexString(start)); 135 readFile(); 136 if (discourageUpload) 137 ds.setUploadPolicy(UploadPolicy.DISCOURAGED); 138 } catch (IOException e) { 139 Logging.error(e); 140 } 141 } 142 143 private void readFile() throws IOException, O5mParsingCancelException { 144 boolean done = false; 145 while (!done) { 146 if (cancel) { 147 cancel = false; 148 throw new O5mParsingCancelException(tr("Reading was canceled at file offset {0}", countBytes)); 149 } 113 150 is = fis; 114 this.cnvBuffer = new byte[4000]; // OSM data should not contain string pairs with length > 512 115 this.ioBuf = new byte[8192]; 116 this.ioPos = 0; 117 this.stringPair = new String[2]; 118 this.lastRef = new long[3]; 119 reset(); 120 } 121 122 /** 123 * parse the input stream 124 */ 125 public void parse() { 126 try { 127 int start = is.read(); 128 ++countBytes; 129 if (start != RESET_FLAG) 130 throw new IOException(tr("wrong header byte ") + Integer.toHexString(start)); 131 readFile(); 132 if (discourageUpload) 133 ds.setUploadPolicy(UploadPolicy.DISCOURAGED); 134 } catch (IOException e) { 135 Logging.error(e); 136 } 137 } 138 139 private void readFile() throws IOException { 140 boolean done = false; 141 while (!done) { 142 is = fis; 143 long size = 0; 144 int fileType = is.read(); 145 ++countBytes; 146 if (fileType >= 0 && fileType < 0xf0) { 147 bytesToRead = 0; 148 size = readUnsignedNum64FromStream(); 149 countBytes += size - bytesToRead; // bytesToRead is negative 150 bytesToRead = (int) size; 151 152 switch(fileType) { 153 case NODE_DATASET: 154 case WAY_DATASET: 155 case REL_DATASET: 156 case BBOX_DATASET: 157 case TIMESTAMP_DATASET: 158 case HEADER_DATASET: 159 if (bytesToRead > ioBuf.length) { 160 ioBuf = new byte[bytesToRead+100]; 161 } 162 int bytesRead = 0; 163 int neededBytes = bytesToRead; 164 while (neededBytes > 0) { 165 bytesRead += is.read(ioBuf, bytesRead, neededBytes); 166 neededBytes -= bytesRead; 167 } 168 ioPos = 0; 169 bis = new ByteArrayInputStream(ioBuf, 0, bytesToRead); 170 is = bis; 171 break; 172 default: 151 long size = 0; 152 int fileType = is.read(); 153 ++countBytes; 154 if (fileType >= 0 && fileType < 0xf0) { 155 bytesToRead = 0; 156 size = readUnsignedNum64FromStream(); 157 countBytes += size - bytesToRead; // bytesToRead is negative 158 bytesToRead = (int) size; 159 160 switch(fileType) { 161 case NODE_DATASET: 162 case WAY_DATASET: 163 case REL_DATASET: 164 case BBOX_DATASET: 165 case TIMESTAMP_DATASET: 166 case HEADER_DATASET: 167 if (bytesToRead > ioBuf.length) { 168 ioBuf = new byte[bytesToRead+100]; 173 169 } 170 int bytesRead = 0; 171 int neededBytes = bytesToRead; 172 while (neededBytes > 0) { 173 bytesRead += is.read(ioBuf, bytesRead, neededBytes); 174 neededBytes -= bytesRead; 175 } 176 ioPos = 0; 177 bis = new ByteArrayInputStream(ioBuf, 0, bytesToRead); 178 is = bis; 179 break; 180 default: 174 181 } 175 if (fileType == EOF_FLAG) done = true; 176 else if (fileType == NODE_DATASET) readNode(); 177 else if (fileType == WAY_DATASET) readWay(); 178 else if (fileType == REL_DATASET) readRel(); 179 else if (fileType == BBOX_DATASET) readBBox(); 180 else if (fileType == TIMESTAMP_DATASET) readFileTimestamp(); 181 else if (fileType == HEADER_DATASET) readHeader(); 182 else if (fileType == EOD_FLAG) done = true; 183 else if (fileType == RESET_FLAG) reset(); 184 else { 185 if (fileType < 0xf0) skip(size); // skip unknown data set 182 } 183 if (fileType == EOF_FLAG) done = true; 184 else if (fileType == NODE_DATASET) readNode(); 185 else if (fileType == WAY_DATASET) readWay(); 186 else if (fileType == REL_DATASET) readRel(); 187 else if (fileType == BBOX_DATASET) readBBox(); 188 else if (fileType == TIMESTAMP_DATASET) readFileTimestamp(); 189 else if (fileType == HEADER_DATASET) readHeader(); 190 else if (fileType == EOD_FLAG) done = true; 191 else if (fileType == RESET_FLAG) reset(); 192 else { 193 if (fileType < 0xf0) skip(size); // skip unknown data set 194 } 195 } 196 } 197 198 /** 199 * read (and ignore) the file timestamp data set 200 */ 201 private void readFileTimestamp() { 202 /*long fileTimeStamp = */readSignedNum64(); 203 } 204 205 /** 206 * Skip the given number of bytes 207 * @param bytes number of bytes to skip 208 * @throws IOException in case of I/O error 209 */ 210 private void skip(long bytes) throws IOException { 211 long toSkip = bytes; 212 while (toSkip > 0) { 213 toSkip -= is.skip(toSkip); 214 } 215 } 216 217 /** 218 * read the bounding box data set 219 */ 220 private void readBBox() { 221 double minlon = FACTOR * 100L * readSignedNum32(); 222 double minlat = FACTOR * 100L * readSignedNum32(); 223 double maxlon = FACTOR * 100L * readSignedNum32(); 224 double maxlat = FACTOR * 100L * readSignedNum32(); 225 226 Bounds b = new Bounds(minlat, minlon, maxlat, maxlon); 227 if (!b.isCollapsed() && LatLon.isValidLat(minlat) && LatLon.isValidLat(maxlat) 228 && LatLon.isValidLon(minlon) && LatLon.isValidLon(maxlon)) { 229 ds.addDataSource(new DataSource(b, header)); 230 } else { 231 Logging.error("Invalid Bounds: "+b); 232 } 233 } 234 235 /** 236 * read a node data set 237 * @throws IOException in case of I/O error 238 */ 239 private void readNode() throws IOException { 240 if (exception != null) 241 return; 242 try { 243 lastNodeId += readSignedNum64(); 244 if (bytesToRead == 0) 245 return; // only nodeId: this is a delete action, we ignore it 246 readVersionTsAuthor(); 247 248 if (bytesToRead == 0) 249 return; // only nodeId+version: this is a delete action, we ignore it 250 int lon = readSignedNum32() + lastLon; lastLon = lon; 251 int lat = readSignedNum32() + lastLat; lastLat = lat; 252 253 double flon = FACTOR * (100L*lon); 254 double flat = FACTOR * (100L*lat); 255 assert flat >= -90.0 && flat <= 90.0; 256 assert flon >= -180.0 && flon <= 180.0; 257 if (version == 0) 258 discourageUpload = true; 259 Node node = new Node(lastNodeId, version == 0 ? 1 : version); 260 node.setCoor(new LatLon(flat, flon).getRoundedToOsmPrecision()); 261 262 263 checkCoordinates(node.getCoor()); 264 checkChangesetId(lastChangeSet); 265 node.setChangesetId((int) lastChangeSet); 266 // User id 267 if (lastTs != 0) { 268 checkTimestamp(lastTs); 269 node.setTimestamp(new Date(lastTs * 1000)); 270 if (osmUser != null) 271 node.setUser(osmUser); 272 } 273 if (bytesToRead > 0) { 274 Map<String, String> keys = readTags(); 275 node.setKeys(keys); 276 } 277 externalIdMap.put(node.getPrimitiveId(), node); 278 } catch (IllegalDataException e) { 279 exception = e; 280 } 281 282 } 283 284 /** 285 * read a way data set 286 * @throws IOException in case of I/O error 287 */ 288 private void readWay() throws IOException { 289 if (exception != null) 290 return; 291 try { 292 lastWayId += readSignedNum64(); 293 if (bytesToRead == 0) 294 return; // only wayId: this is a delete action, we ignore it 295 296 readVersionTsAuthor(); 297 if (bytesToRead == 0) 298 return; // only wayId + version: this is a delete action, we ignore it 299 if (version == 0) 300 discourageUpload = true; 301 final Way way = new Way(lastWayId, version == 0 ? 1 : version); 302 checkChangesetId(lastChangeSet); 303 way.setChangesetId((int) lastChangeSet); 304 // User id 305 if (lastTs != 0) { 306 checkTimestamp(lastTs); 307 way.setTimestamp(new Date(lastTs * 1000)); 308 if (osmUser != null) 309 way.setUser(osmUser); 310 } 311 312 long refSize = readUnsignedNum32(); 313 long stop = bytesToRead - refSize; 314 Collection<Long> nodeIds = new ArrayList<>(); 315 316 while (bytesToRead > stop) { 317 lastRef[0] += readSignedNum64(); 318 nodeIds.add(lastRef[0]); 319 } 320 321 Map<String, String> keys = readTags(); 322 way.setKeys(keys); 323 ways.put(way.getUniqueId(), nodeIds); 324 externalIdMap.put(way.getPrimitiveId(), way); 325 } catch (IllegalDataException e) { 326 exception = e; 327 } 328 329 } 330 331 /** 332 * read a relation data set 333 * @throws IOException in case of I/O error 334 */ 335 private void readRel() throws IOException { 336 if (exception != null) 337 return; 338 try { 339 lastRelId += readSignedNum64(); 340 if (bytesToRead == 0) 341 return; // only relId: this is a delete action, we ignore it 342 readVersionTsAuthor(); 343 if (bytesToRead == 0) 344 return; // only relId + version: this is a delete action, we ignore it 345 if (version == 0) 346 discourageUpload = true; 347 final Relation rel = new Relation(lastRelId, version == 0 ? 1 : version); 348 checkChangesetId(lastChangeSet); 349 rel.setChangesetId((int) lastChangeSet); 350 if (lastTs != 0) { 351 checkTimestamp(lastTs); 352 rel.setTimestamp(new Date(lastTs * 1000)); 353 if (osmUser != null) 354 rel.setUser(osmUser); 355 } 356 357 long refSize = readUnsignedNum32(); 358 long stop = bytesToRead - refSize; 359 Collection<RelationMemberData> members = new ArrayList<>(); 360 while (bytesToRead > stop) { 361 long deltaRef = readSignedNum64(); 362 int refType = readRelRef(); 363 String role = stringPair[1]; 364 lastRef[refType] += deltaRef; 365 long memId = lastRef[refType]; 366 OsmPrimitiveType type = null; 367 368 if (refType == 0) { 369 type = OsmPrimitiveType.NODE; 370 } else if (refType == 1) { 371 type = OsmPrimitiveType.WAY; 372 } else if (refType == 2) { 373 type = OsmPrimitiveType.RELATION; 186 374 } 187 } 188 } 189 190 /** 191 * read (and ignore) the file timestamp data set 192 */ 193 private void readFileTimestamp() { 194 /*long fileTimeStamp = */readSignedNum64(); 195 } 196 197 /** 198 * Skip the given number of bytes 199 * @param bytes number of bytes to skip 200 * @throws IOException in case of I/O error 201 */ 202 private void skip(long bytes) throws IOException { 203 long toSkip = bytes; 204 while (toSkip > 0) { 205 toSkip -= is.skip(toSkip); 206 } 207 } 208 209 /** 210 * read the bounding box data set 211 */ 212 private void readBBox() { 213 double minlon = FACTOR * 100L * readSignedNum32(); 214 double minlat = FACTOR * 100L * readSignedNum32(); 215 double maxlon = FACTOR * 100L * readSignedNum32(); 216 double maxlat = FACTOR * 100L * readSignedNum32(); 217 218 Bounds b = new Bounds(minlat, minlon, maxlat, maxlon); 219 if (!b.isCollapsed() && LatLon.isValidLat(minlat) && LatLon.isValidLat(maxlat) 220 && LatLon.isValidLon(minlon) && LatLon.isValidLon(maxlon)) { 221 ds.addDataSource(new DataSource(b, header)); 222 } else { 223 Logging.error("Invalid Bounds: "+b); 224 } 225 } 226 227 /** 228 * read a node data set 229 * @throws IOException in case of I/O error 230 */ 231 private void readNode() throws IOException { 232 if (exception != null) 233 return; 234 try { 235 lastNodeId += readSignedNum64(); 236 if (bytesToRead == 0) 237 return; // only nodeId: this is a delete action, we ignore it 238 readVersionTsAuthor(); 239 240 if (bytesToRead == 0) 241 return; // only nodeId+version: this is a delete action, we ignore it 242 int lon = readSignedNum32() + lastLon; lastLon = lon; 243 int lat = readSignedNum32() + lastLat; lastLat = lat; 244 245 double flon = FACTOR * (100L*lon); 246 double flat = FACTOR * (100L*lat); 247 assert flat >= -90.0 && flat <= 90.0; 248 assert flon >= -180.0 && flon <= 180.0; 249 if (version == 0) 250 discourageUpload = true; 251 Node node = new Node(lastNodeId, version == 0 ? 1 : version); 252 node.setCoor(new LatLon(flat, flon).getRoundedToOsmPrecision()); 253 254 255 checkCoordinates(node.getCoor()); 256 checkChangesetId(lastChangeSet); 257 node.setChangesetId((int) lastChangeSet); 258 // User id 259 if (lastTs != 0) { 260 checkTimestamp(lastTs); 261 node.setTimestamp(new Date(lastTs * 1000)); 262 if (osmUser != null) 263 node.setUser(osmUser); 375 members.add(new RelationMemberData(role, type, memId)); 376 } 377 Map<String, String> keys = readTags(); 378 rel.setKeys(keys); 379 relations.put(rel.getUniqueId(), members); 380 externalIdMap.put(rel.getPrimitiveId(), rel); 381 } catch (IllegalDataException e) { 382 exception = e; 383 } 384 } 385 386 private Map<String, String> readTags() throws IOException { 387 Map<String, String> keys = new HashMap<>(); 388 while (bytesToRead > 0) { 389 readStringPair(); 390 keys.put(stringPair[0], stringPair[1]); 391 } 392 assert bytesToRead == 0; 393 return keys; 394 } 395 396 /** 397 * Store a new string pair (length check must be performed by caller) 398 */ 399 private void storeStringPair() { 400 stringTable[0][currStringTablePos] = stringPair[0]; 401 stringTable[1][currStringTablePos] = stringPair[1]; 402 ++currStringTablePos; 403 if (currStringTablePos >= STRING_TABLE_SIZE) 404 currStringTablePos = 0; 405 } 406 407 /** 408 * set stringPair to the values referenced by given string reference 409 * No checking is performed. 410 * @param ref valid values are 1 .. STRING_TABLE_SIZE 411 */ 412 private void setStringRefPair(int ref) { 413 int pos = currStringTablePos - ref; 414 if (pos < 0) 415 pos += STRING_TABLE_SIZE; 416 stringPair[0] = stringTable[0][pos]; 417 stringPair[1] = stringTable[1][pos]; 418 } 419 420 /** 421 * Read version, time stamp and change set and author. 422 * We are not interested in the values, but we have to maintain the string table. 423 * @throws IOException in case of I/O error 424 */ 425 private void readVersionTsAuthor() throws IOException { 426 stringPair[0] = null; 427 stringPair[1] = null; 428 version = readUnsignedNum32(); 429 if (version != 0) { 430 // version info 431 long ts = readSignedNum64() + lastTs; lastTs = ts; 432 if (ts != 0) { 433 long changeSet = readSignedNum32() + lastChangeSet; lastChangeSet = changeSet; 434 readAuthor(); 435 } 436 } 437 } 438 439 /** 440 * Read author . 441 * @throws IOException in case of I/O error 442 */ 443 private void readAuthor() throws IOException { 444 int stringRef = readUnsignedNum32(); 445 if (stringRef == 0) { 446 long toReadStart = bytesToRead; 447 long uidNum = readUnsignedNum64(); 448 if (uidNum == 0) 449 stringPair[0] = ""; 450 else { 451 stringPair[0] = Long.toString(uidNum); 452 ioPos++; // skip terminating zero from uid 453 --bytesToRead; 454 } 455 int start = 0; 456 int buffPos = 0; 457 stringPair[1] = null; 458 while (stringPair[1] == null) { 459 final int b = ioBuf[ioPos++]; 460 --bytesToRead; 461 cnvBuffer[buffPos++] = (byte) b; 462 463 if (b == 0) 464 stringPair[1] = new String(cnvBuffer, start, buffPos-1, "UTF-8"); 465 } 466 long bytes = toReadStart - bytesToRead; 467 if (bytes <= MAX_STRING_PAIR_SIZE) 468 storeStringPair(); 469 } else 470 setStringRefPair(stringRef); 471 if (stringPair[0] != null && stringPair[0].isEmpty() == false) { 472 long uid = Long.parseLong(stringPair[0]); 473 osmUser = User.createOsmUser(uid, stringPair[1]); 474 } else 475 osmUser = null; 476 } 477 478 /** 479 * read object type ("0".."2") concatenated with role (single string) 480 * @return 0..3 for type (3 means unknown) 481 * @throws IOException in case of I/O error 482 */ 483 private int readRelRef() throws IOException { 484 int refType = -1; 485 long toReadStart = bytesToRead; 486 int stringRef = readUnsignedNum32(); 487 if (stringRef == 0) { 488 refType = ioBuf[ioPos++] - 0x30; 489 --bytesToRead; 490 491 if (refType < 0 || refType > 2) 492 refType = 3; 493 stringPair[0] = REL_REF_TYPES[refType]; 494 495 int start = 0; 496 int buffPos = 0; 497 stringPair[1] = null; 498 while (stringPair[1] == null) { 499 final int b = ioBuf[ioPos++]; 500 --bytesToRead; 501 cnvBuffer[buffPos++] = (byte) b; 502 503 if (b == 0) 504 stringPair[1] = new String(cnvBuffer, start, buffPos-1, "UTF-8"); 505 } 506 long bytes = toReadStart - bytesToRead; 507 if (bytes <= MAX_STRING_PAIR_SIZE) 508 storeStringPair(); 509 } else { 510 setStringRefPair(stringRef); 511 char c = stringPair[0].charAt(0); 512 switch (c) { 513 case 'n': refType = 0; break; 514 case 'w': refType = 1; break; 515 case 'r': refType = 2; break; 516 default: refType = 3; 517 } 518 } 519 return refType; 520 } 521 522 /** 523 * read a string pair (see o5m definition) 524 * @throws IOException in case of I/O error 525 */ 526 private void readStringPair() throws IOException { 527 int stringRef = readUnsignedNum32(); 528 if (stringRef == 0) { 529 long toReadStart = bytesToRead; 530 int cnt = 0; 531 int buffPos = 0; 532 int start = 0; 533 while (cnt < 2) { 534 final int b = ioBuf[ioPos++]; 535 --bytesToRead; 536 cnvBuffer[buffPos++] = (byte) b; 537 538 if (b == 0) { 539 stringPair[cnt] = new String(cnvBuffer, start, buffPos-start-1, "UTF-8"); 540 ++cnt; 541 start = buffPos; 264 542 } 265 if (bytesToRead > 0) { 266 Map<String, String> keys = readTags(); 267 node.setKeys(keys); 268 } 269 externalIdMap.put(node.getPrimitiveId(), node); 270 } catch (IllegalDataException e) { 271 exception = e; 272 } 273 274 } 275 276 /** 277 * read a way data set 278 * @throws IOException in case of I/O error 279 */ 280 private void readWay() throws IOException { 281 if (exception != null) 282 return; 283 try { 284 lastWayId += readSignedNum64(); 285 if (bytesToRead == 0) 286 return; // only wayId: this is a delete action, we ignore it 287 288 readVersionTsAuthor(); 289 if (bytesToRead == 0) 290 return; // only wayId + version: this is a delete action, we ignore it 291 if (version == 0) 292 discourageUpload = true; 293 final Way way = new Way(lastWayId, version == 0 ? 1 : version); 294 checkChangesetId(lastChangeSet); 295 way.setChangesetId((int) lastChangeSet); 296 // User id 297 if (lastTs != 0) { 298 checkTimestamp(lastTs); 299 way.setTimestamp(new Date(lastTs * 1000)); 300 if (osmUser != null) 301 way.setUser(osmUser); 302 } 303 304 long refSize = readUnsignedNum32(); 305 long stop = bytesToRead - refSize; 306 Collection<Long> nodeIds = new ArrayList<>(); 307 308 while (bytesToRead > stop) { 309 lastRef[0] += readSignedNum64(); 310 nodeIds.add(lastRef[0]); 311 } 312 313 Map<String, String> keys = readTags(); 314 way.setKeys(keys); 315 ways.put(way.getUniqueId(), nodeIds); 316 externalIdMap.put(way.getPrimitiveId(), way); 317 } catch (IllegalDataException e) { 318 exception = e; 319 } 320 321 } 322 323 /** 324 * read a relation data set 325 * @throws IOException in case of I/O error 326 */ 327 private void readRel() throws IOException { 328 if (exception != null) 329 return; 330 try { 331 lastRelId += readSignedNum64(); 332 if (bytesToRead == 0) 333 return; // only relId: this is a delete action, we ignore it 334 readVersionTsAuthor(); 335 if (bytesToRead == 0) 336 return; // only relId + version: this is a delete action, we ignore it 337 if (version == 0) 338 discourageUpload = true; 339 final Relation rel = new Relation(lastRelId, version == 0 ? 1 : version); 340 checkChangesetId(lastChangeSet); 341 rel.setChangesetId((int) lastChangeSet); 342 if (lastTs != 0) { 343 checkTimestamp(lastTs); 344 rel.setTimestamp(new Date(lastTs * 1000)); 345 if (osmUser != null) 346 rel.setUser(osmUser); 347 } 348 349 long refSize = readUnsignedNum32(); 350 long stop = bytesToRead - refSize; 351 Collection<RelationMemberData> members = new ArrayList<>(); 352 while (bytesToRead > stop) { 353 long deltaRef = readSignedNum64(); 354 int refType = readRelRef(); 355 String role = stringPair[1]; 356 lastRef[refType] += deltaRef; 357 long memId = lastRef[refType]; 358 OsmPrimitiveType type = null; 359 360 if (refType == 0) { 361 type = OsmPrimitiveType.NODE; 362 } else if (refType == 1) { 363 type = OsmPrimitiveType.WAY; 364 } else if (refType == 2) { 365 type = OsmPrimitiveType.RELATION; 366 } 367 members.add(new RelationMemberData(role, type, memId)); 368 } 369 Map<String, String> keys = readTags(); 370 rel.setKeys(keys); 371 relations.put(rel.getUniqueId(), members); 372 externalIdMap.put(rel.getPrimitiveId(), rel); 373 } catch (IllegalDataException e) { 374 exception = e; 375 } 376 } 377 378 private Map<String, String> readTags() throws IOException { 379 Map<String, String> keys = new HashMap<>(); 380 while (bytesToRead > 0) { 381 readStringPair(); 382 keys.put(stringPair[0], stringPair[1]); 383 } 384 assert bytesToRead == 0; 385 return keys; 386 } 387 388 /** 389 * Store a new string pair (length check must be performed by caller) 390 */ 391 private void storeStringPair() { 392 stringTable[0][currStringTablePos] = stringPair[0]; 393 stringTable[1][currStringTablePos] = stringPair[1]; 394 ++currStringTablePos; 395 if (currStringTablePos >= STRING_TABLE_SIZE) 396 currStringTablePos = 0; 397 } 398 399 /** 400 * set stringPair to the values referenced by given string reference 401 * No checking is performed. 402 * @param ref valid values are 1 .. STRING_TABLE_SIZE 403 */ 404 private void setStringRefPair(int ref) { 405 int pos = currStringTablePos - ref; 406 if (pos < 0) 407 pos += STRING_TABLE_SIZE; 408 stringPair[0] = stringTable[0][pos]; 409 stringPair[1] = stringTable[1][pos]; 410 } 411 412 /** 413 * Read version, time stamp and change set and author. 414 * We are not interested in the values, but we have to maintain the string table. 415 * @throws IOException in case of I/O error 416 */ 417 private void readVersionTsAuthor() throws IOException { 418 stringPair[0] = null; 419 stringPair[1] = null; 420 version = readUnsignedNum32(); 421 if (version != 0) { 422 // version info 423 long ts = readSignedNum64() + lastTs; lastTs = ts; 424 if (ts != 0) { 425 long changeSet = readSignedNum32() + lastChangeSet; lastChangeSet = changeSet; 426 readAuthor(); 427 } 428 } 429 } 430 431 /** 432 * Read author . 433 * @throws IOException in case of I/O error 434 */ 435 private void readAuthor() throws IOException { 436 int stringRef = readUnsignedNum32(); 437 if (stringRef == 0) { 438 long toReadStart = bytesToRead; 439 long uidNum = readUnsignedNum64(); 440 if (uidNum == 0) 441 stringPair[0] = ""; 442 else { 443 stringPair[0] = Long.toString(uidNum); 444 ioPos++; // skip terminating zero from uid 445 --bytesToRead; 446 } 447 int start = 0; 448 int buffPos = 0; 449 stringPair[1] = null; 450 while (stringPair[1] == null) { 451 final int b = ioBuf[ioPos++]; 452 --bytesToRead; 453 cnvBuffer[buffPos++] = (byte) b; 454 455 if (b == 0) 456 stringPair[1] = new String(cnvBuffer, start, buffPos-1, "UTF-8"); 457 } 458 long bytes = toReadStart - bytesToRead; 459 if (bytes <= MAX_STRING_PAIR_SIZE) 460 storeStringPair(); 461 } else 462 setStringRefPair(stringRef); 463 if (stringPair[0] != null && stringPair[0].isEmpty() == false) { 464 long uid = Long.parseLong(stringPair[0]); 465 osmUser = User.createOsmUser(uid, stringPair[1]); 466 } else 467 osmUser = null; 468 } 469 470 /** 471 * read object type ("0".."2") concatenated with role (single string) 472 * @return 0..3 for type (3 means unknown) 473 * @throws IOException in case of I/O error 474 */ 475 private int readRelRef() throws IOException { 476 int refType = -1; 477 long toReadStart = bytesToRead; 478 int stringRef = readUnsignedNum32(); 479 if (stringRef == 0) { 480 refType = ioBuf[ioPos++] - 0x30; 481 --bytesToRead; 482 483 if (refType < 0 || refType > 2) 484 refType = 3; 485 stringPair[0] = REL_REF_TYPES[refType]; 486 487 int start = 0; 488 int buffPos = 0; 489 stringPair[1] = null; 490 while (stringPair[1] == null) { 491 final int b = ioBuf[ioPos++]; 492 --bytesToRead; 493 cnvBuffer[buffPos++] = (byte) b; 494 495 if (b == 0) 496 stringPair[1] = new String(cnvBuffer, start, buffPos-1, "UTF-8"); 497 } 498 long bytes = toReadStart - bytesToRead; 499 if (bytes <= MAX_STRING_PAIR_SIZE) 500 storeStringPair(); 501 } else { 502 setStringRefPair(stringRef); 503 char c = stringPair[0].charAt(0); 504 switch (c) { 505 case 'n': refType = 0; break; 506 case 'w': refType = 1; break; 507 case 'r': refType = 2; break; 508 default: refType = 3; 509 } 510 } 511 return refType; 512 } 513 514 /** 515 * read a string pair (see o5m definition) 516 * @throws IOException in case of I/O error 517 */ 518 private void readStringPair() throws IOException { 519 int stringRef = readUnsignedNum32(); 520 if (stringRef == 0) { 521 long toReadStart = bytesToRead; 522 int cnt = 0; 523 int buffPos = 0; 524 int start = 0; 525 while (cnt < 2) { 526 final int b = ioBuf[ioPos++]; 527 --bytesToRead; 528 cnvBuffer[buffPos++] = (byte) b; 529 530 if (b == 0) { 531 stringPair[cnt] = new String(cnvBuffer, start, buffPos-start-1, "UTF-8"); 532 ++cnt; 533 start = buffPos; 534 } 535 } 536 long bytes = toReadStart - bytesToRead; 537 if (bytes <= MAX_STRING_PAIR_SIZE) 538 storeStringPair(); 539 } else 540 setStringRefPair(stringRef); 541 } 542 543 /** reset the delta values and string table */ 544 private void reset() { 545 lastNodeId = 0; lastWayId = 0; lastRelId = 0; 546 lastRef[0] = 0; lastRef[1] = 0; lastRef[2] = 0; 547 lastTs = 0; lastChangeSet = 0; 548 lastLon = 0; lastLat = 0; 549 stringTable = new String[2][STRING_TABLE_SIZE]; 550 currStringTablePos = 0; 551 } 552 553 /** 554 * read and verify o5m header (known values are o5m2 and o5c2) 555 * @throws IOException in case of I/O error 556 */ 557 private void readHeader() throws IOException { 558 if (ioBuf[0] != 'o' || ioBuf[1] != '5' || (ioBuf[2] != 'c' && ioBuf[2] != 'm') || ioBuf[3] != '2') { 559 throw new IOException(tr("unsupported header")); 560 } 561 header = new String(ioBuf, 0, 3, "UTF-8"); 562 } 563 564 /** 565 * read a varying length signed number (see o5m definition) 566 * @return the number 567 */ 568 private int readSignedNum32() { 569 int result; 570 int b = ioBuf[ioPos++]; 543 } 544 long bytes = toReadStart - bytesToRead; 545 if (bytes <= MAX_STRING_PAIR_SIZE) 546 storeStringPair(); 547 } else 548 setStringRefPair(stringRef); 549 } 550 551 /** reset the delta values and string table */ 552 private void reset() { 553 lastNodeId = 0; lastWayId = 0; lastRelId = 0; 554 lastRef[0] = 0; lastRef[1] = 0; lastRef[2] = 0; 555 lastTs = 0; lastChangeSet = 0; 556 lastLon = 0; lastLat = 0; 557 stringTable = new String[2][STRING_TABLE_SIZE]; 558 currStringTablePos = 0; 559 } 560 561 /** 562 * read and verify o5m header (known values are o5m2 and o5c2) 563 * @throws IOException in case of I/O error 564 */ 565 private void readHeader() throws IOException { 566 if (ioBuf[0] != 'o' || ioBuf[1] != '5' || (ioBuf[2] != 'c' && ioBuf[2] != 'm') || ioBuf[3] != '2') { 567 throw new IOException(tr("unsupported header")); 568 } 569 header = new String(ioBuf, 0, 3, "UTF-8"); 570 } 571 572 /** 573 * read a varying length signed number (see o5m definition) 574 * @return the number as int 575 */ 576 private int readSignedNum32() { 577 int result; 578 int b = ioBuf[ioPos++]; 579 --bytesToRead; 580 result = b; 581 if ((b & 0x80) == 0) { // just one byte 582 if ((b & 0x01) == 1) 583 return -1-(result >> 1); 584 return result >> 1; 585 } 586 int sign = b & 0x01; 587 result = (result & 0x7e) >> 1; 588 int shift = 6; 589 while (((b = ioBuf[ioPos++]) & 0x80) != 0) { // more bytes will follow 571 590 --bytesToRead; 572 result = b; 573 if ((b & 0x80) == 0) { // just one byte 574 if ((b & 0x01) == 1) 575 return -1-(result >> 1); 576 return result >> 1; 577 } 578 int sign = b & 0x01; 579 result = (result & 0x7e) >> 1; 580 int fac = 0x40; 581 while (((b = ioBuf[ioPos++]) & 0x80) != 0) { // more bytes will follow 582 --bytesToRead; 583 result += fac * (b & 0x7f); 584 fac <<= 7; 585 } 591 result += (b & 0x7f) << shift; 592 shift += 7; 593 } 594 --bytesToRead; 595 result += b << shift; 596 if (sign == 1) // negative 597 return -1 - result; 598 return result; 599 600 } 601 602 /** 603 * read a varying length signed number (see o5m definition) 604 * @return the number as long 605 */ 606 private long readSignedNum64() { 607 long result; 608 int b = ioBuf[ioPos++]; 609 --bytesToRead; 610 result = b; 611 if ((b & 0x80) == 0) { // just one byte 612 if ((b & 0x01) == 1) 613 return -1 - (result >> 1); 614 return result >> 1; 615 } 616 int sign = b & 0x01; 617 result = (result & 0x7e) >> 1; 618 int shift = 6; 619 while (((b = ioBuf[ioPos++]) & 0x80) != 0) { // more bytes will follow 586 620 --bytesToRead; 587 result += fac * b; 588 if (sign == 1) // negative 589 return -1-result; 621 result += ((long) (b & 0x7f)) << shift; 622 shift += 7; 623 } 624 --bytesToRead; 625 result += ((long) b) << shift; 626 if (sign == 1) // negative 627 return -1 - result; 628 return result; 629 } 630 631 /** 632 * read a varying length unsigned number (see o5m definition) 633 * @return the number as long 634 * @throws IOException in case of I/O error 635 */ 636 private long readUnsignedNum64FromStream()throws IOException { 637 int b = is.read(); 638 --bytesToRead; 639 long result = b; 640 if ((b & 0x80) == 0) { // just one byte 590 641 return result; 591 592 } 593 594 /** 595 * read a varying length signed number (see o5m definition) 596 * @return the number 597 */ 598 private long readSignedNum64() { 599 long result; 600 int b = ioBuf[ioPos++]; 642 } 643 result &= 0x7f; 644 int shift = 7; 645 while (((b = is.read()) & 0x80) != 0) { // more bytes will follow 601 646 --bytesToRead; 602 result = b; 603 if ((b & 0x80) == 0) { // just one byte 604 if ((b & 0x01) == 1) 605 return -1-(result >> 1); 606 return result >> 1; 607 } 608 int sign = b & 0x01; 609 result = (result & 0x7e) >> 1; 610 long fac = 0x40; 611 while (((b = ioBuf[ioPos++]) & 0x80) != 0) { // more bytes will follow 612 --bytesToRead; 613 result += fac * (b & 0x7f); 614 fac <<= 7; 615 } 647 result += ((long) (b & 0x7f)) << shift; 648 shift += 7; 649 } 650 --bytesToRead; 651 result += ((long) b) << shift; 652 return result; 653 } 654 655 656 /** 657 * read a varying length unsigned number (see o5m definition) 658 * @return the number as long 659 */ 660 private long readUnsignedNum64() { 661 int b = ioBuf[ioPos++]; 662 --bytesToRead; 663 long result = b; 664 if ((b & 0x80) == 0) { // just one byte 665 return result; 666 } 667 result &= 0x7f; 668 int shift = 7; 669 while (((b = ioBuf[ioPos++]) & 0x80) != 0) { // more bytes will follow 616 670 --bytesToRead; 617 result += fac * b; 618 if (sign == 1) // negative 619 return -1-result; 671 result += ((long) (b & 0x7f)) << shift; 672 shift += 7; 673 } 674 --bytesToRead; 675 result += ((long) b) << shift; 676 return result; 677 } 678 679 /** 680 * read a varying length unsigned number (see o5m definition) 681 * is similar to the 64 bit version. 682 * @return the number as int 683 */ 684 private int readUnsignedNum32() { 685 int b = ioBuf[ioPos++]; 686 --bytesToRead; 687 int result = b; 688 if ((b & 0x80) == 0) { // just one byte 620 689 return result; 621 622 } 623 624 /** 625 * read a varying length unsigned number (see o5m definition) 626 * @return a long 627 * @throws IOException in case of I/O error 628 */ 629 private long readUnsignedNum64FromStream()throws IOException { 630 int b = is.read(); 690 } 691 result &= 0x7f; 692 int shift = 7; 693 while (((b = ioBuf[ioPos++]) & 0x80) != 0) { // more bytes will follow 631 694 --bytesToRead; 632 long result = b; 633 if ((b & 0x80) == 0) { // just one byte 634 return result; 635 } 636 result &= 0x7f; 637 long fac = 0x80; 638 while (((b = is.read()) & 0x80) != 0) { // more bytes will follow 639 --bytesToRead; 640 result += fac * (b & 0x7f); 641 fac <<= 7; 642 } 643 --bytesToRead; 644 result += fac * b; 645 return result; 646 } 647 648 649 /** 650 * read a varying length unsigned number (see o5m definition) 651 * @return a long 652 */ 653 private long readUnsignedNum64() { 654 int b = ioBuf[ioPos++]; 655 --bytesToRead; 656 long result = b; 657 if ((b & 0x80) == 0) { // just one byte 658 return result; 659 } 660 result &= 0x7f; 661 long fac = 0x80; 662 while (((b = ioBuf[ioPos++]) & 0x80) != 0) { // more bytes will follow 663 --bytesToRead; 664 result += fac * (b & 0x7f); 665 fac <<= 7; 666 } 667 --bytesToRead; 668 result += fac * b; 669 return result; 670 } 671 672 /** 673 * read a varying length unsigned number (see o5m definition) 674 * is similar to the 64 bit version. 675 * @return an int 676 */ 677 private int readUnsignedNum32() { 678 int b = ioBuf[ioPos++]; 679 --bytesToRead; 680 int result = b; 681 if ((b & 0x80) == 0) { // just one byte 682 return result; 683 } 684 result &= 0x7f; 685 long fac = 0x80; 686 while (((b = ioBuf[ioPos++]) & 0x80) != 0) { // more bytes will follow 687 --bytesToRead; 688 result += fac * (b & 0x7f); 689 fac <<= 7; 690 } 691 --bytesToRead; 692 result += fac * b; 693 return result; 694 } 695 696 695 result += (b & 0x7f) << shift; 696 shift += 7; 697 } 698 --bytesToRead; 699 result += b << shift; 700 return result; 701 } 702 703 /** 704 * Exception thrown after user cancellation. 705 */ 706 private static final class O5mParsingCancelException extends Exception implements ImportCancelException { 707 O5mParsingCancelException(String msg) { 708 super(msg); 709 } 710 } 697 711 698 712 /** … … 711 725 } 712 726 CheckParameterUtil.ensureParameterNotNull(source, "source"); 713 return new O5mReader( source).doParseDataSet(source, progressMonitor);727 return new O5mReader().doParseDataSet(source, progressMonitor); 714 728 } 715 729 … … 717 731 protected DataSet doParseDataSet(InputStream source, ProgressMonitor progressMonitor) 718 732 throws IllegalDataException { 733 ProgressMonitor.CancelListener cancelListener = () -> cancel = true; 734 progressMonitor.addCancelListener(cancelListener); 719 735 try { 720 progressMonitor.beginTask(tr("Prepare OSM data..." , 2));736 progressMonitor.beginTask(tr("Prepare OSM data..."), 3); // read, prepare, render 721 737 progressMonitor.indeterminateSubTask(tr("Reading OSM data...")); 722 738 723 parse( );739 parse(source); 724 740 progressMonitor.worked(1); 725 741 726 742 progressMonitor.indeterminateSubTask(tr("Preparing data set...")); 727 743 prepareDataSet(); 728 744 progressMonitor.worked(1); 745 if (cancel) { 746 throw new O5mParsingCancelException(tr("Import was canceled while preparing data")); 747 } 748 progressMonitor.indeterminateSubTask(tr("Rendering data set...")); 729 749 return getDataSet(); 730 750 } catch (IllegalDataException e) { … … 733 753 throw new IllegalDataException(e); 734 754 } finally { 735 progressMonitor. finishTask();755 progressMonitor.removeCancelListener(cancelListener); 736 756 } 737 757 }
Note:
See TracChangeset
for help on using the changeset viewer.