private List <Way> processWays(QueryParameters queryParameters, int numberOfWays) { List <Way> ways = new List <Way>(); Tag[] wayTags = this.mapFileHeader.MapFileInfo.WayTags; for (int elementCounter = numberOfWays; elementCounter != 0; --elementCounter) { if (this.mapFileHeader.MapFileInfo.DebugFile) { // get and check the way signature this.signatureWay = this.readBuffer.ReadUTF8Encodedstring(SIGNATURE_LENGTH_WAY); if (!this.signatureWay.StartsWith("---WayStart")) { System.Diagnostics.Debug.WriteLine("invalid way signature: " + this.signatureWay); System.Diagnostics.Debug.WriteLine(DEBUG_SIGNATURE_BLOCK + this.signatureBlock); return(null); } } // get the size of the way (VBE-U) int wayDataSize = this.readBuffer.ReadUnsignedInt(); if (wayDataSize < 0) { System.Diagnostics.Debug.WriteLine("invalid way data size: " + wayDataSize); if (this.mapFileHeader.MapFileInfo.DebugFile) { System.Diagnostics.Debug.WriteLine(DEBUG_SIGNATURE_BLOCK + this.signatureBlock); } return(null); } if (queryParameters.useTileBitmask) { // get the way tile bitmask (2 bytes) int tileBitmask = this.readBuffer.Readshort(); // check if the way is inside the requested tile if ((queryParameters.queryTileBitmask & tileBitmask) == 0) { // skip the rest of the way and continue with the next way this.readBuffer.SkipBytes(wayDataSize - 2); continue; } } else { // ignore the way tile bitmask (2 bytes) this.readBuffer.SkipBytes(2); } // get the special byte which encodes multiple flags byte specialbyte = (byte)this.readBuffer.ReadByte(); // bit 1-4 represent the layer byte layer = (byte)((specialbyte & WAY_LAYER_BITMASK) >> WAY_LAYER_SHIFT); // bit 5-8 represent the number of tag IDs byte numberOfTags = (byte)(specialbyte & WAY_NUMBER_OF_TAGS_BITMASK); List <Tag> tags = new List <Tag>(); for (byte tagIndex = numberOfTags; tagIndex != 0; --tagIndex) { int tagId = this.readBuffer.ReadUnsignedInt(); if (tagId < 0 || tagId >= wayTags.Length) { System.Diagnostics.Debug.WriteLine("invalid way tag ID: " + tagId); return(null); } tags.Add(wayTags[tagId]); } // get the feature bitmask (1 byte) byte featurebyte = (byte)this.readBuffer.ReadByte(); // bit 1-6 enable optional features bool featureName = (featurebyte & WAY_FEATURE_NAME) != 0; bool featureHouseNumber = (featurebyte & WAY_FEATURE_HOUSE_NUMBER) != 0; bool featureRef = (featurebyte & WAY_FEATURE_REF) != 0; bool featureLabelPosition = (featurebyte & WAY_FEATURE_LABEL_POSITION) != 0; bool featureWayDataBlocksbyte = (featurebyte & WAY_FEATURE_DATA_BLOCKS_byte) != 0; bool featureWayDoubleDeltaEncoding = (featurebyte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0; // check if the way has a name if (featureName) { tags.Add(new Tag(TAG_KEY_NAME, this.readBuffer.ReadUTF8Encodedstring())); } // check if the way has a house number if (featureHouseNumber) { tags.Add(new Tag(TAG_KEY_HOUSE_NUMBER, this.readBuffer.ReadUTF8Encodedstring())); } // check if the way has a reference if (featureRef) { tags.Add(new Tag(TAG_KEY_REF, this.readBuffer.ReadUTF8Encodedstring())); } GeoPoint labelPosition = readOptionalLabelPosition(featureLabelPosition); int wayDataBlocks = readOptionalWayDataBlocksbyte(featureWayDataBlocksbyte); if (wayDataBlocks < 1) { System.Diagnostics.Debug.WriteLine("invalid number of way data blocks: " + wayDataBlocks); return(null); } for (int wayDataBlock = 0; wayDataBlock < wayDataBlocks; ++wayDataBlock) { GeoPointList2 wayNodes = processWayDataBlock(featureWayDoubleDeltaEncoding); if (wayNodes == null) { return(null); } ways.Add(new Way(layer, tags, wayNodes, labelPosition)); } } return(ways); }
private MapReadResult processBlocks(QueryParameters queryParameters, SubFileParameter subFileParameter) { bool queryIsWater = true; bool queryReadWaterInfo = false; MapReadResultBuilder mapReadResultBuilder = new MapReadResultBuilder(); // read and process all blocks from top to bottom and from left to right for (long row = queryParameters.fromBlockY; row <= queryParameters.toBlockY; ++row) { for (long column = queryParameters.fromBlockX; column <= queryParameters.toBlockX; ++column) { // calculate the actual block number of the needed block in the file long blockNumber = row * subFileParameter.BlocksWidth + column; // get the current index entry long currentBlockIndexEntry = this.databaseIndexCache.getIndexEntry(subFileParameter, blockNumber); // check if the current query would still return a water tile if (queryIsWater) { // check the water flag of the current block in its index entry queryIsWater &= (currentBlockIndexEntry & BITMASK_INDEX_WATER) != 0; queryReadWaterInfo = true; } // get and check the current block pointer long currentBlockpointer = currentBlockIndexEntry & BITMASK_INDEX_OFFSET; if (currentBlockpointer < 1 || currentBlockpointer > subFileParameter.SubFileSize) { System.Diagnostics.Debug.WriteLine("invalid current block pointer: " + currentBlockpointer); System.Diagnostics.Debug.WriteLine("subFileSize: " + subFileParameter.SubFileSize); return(null); } long nextBlockpointer; // check if the current block is the last block in the file if (blockNumber + 1 == subFileParameter.NumberOfBlocks) { // set the next block pointer to the end of the file nextBlockpointer = subFileParameter.SubFileSize; } else { // get and check the next block pointer nextBlockpointer = this.databaseIndexCache.getIndexEntry(subFileParameter, blockNumber + 1) & BITMASK_INDEX_OFFSET; if (nextBlockpointer > subFileParameter.SubFileSize) { System.Diagnostics.Debug.WriteLine("invalid next block pointer: " + nextBlockpointer); System.Diagnostics.Debug.WriteLine("sub-file size: " + subFileParameter.SubFileSize); return(null); } } // calculate the size of the current block int currentBlockSize = (int)(nextBlockpointer - currentBlockpointer); if (currentBlockSize < 0) { System.Diagnostics.Debug.WriteLine("current block size must not be negative: " + currentBlockSize); return(null); } else if (currentBlockSize == 0) { // the current block is empty, continue with the next block continue; } else if (currentBlockSize > BufferStream.MAXIMUM_BUFFER_SIZE) { // the current block is too large, continue with the next block System.Diagnostics.Debug.WriteLine("current block size too large: " + currentBlockSize); continue; } else if (currentBlockpointer + currentBlockSize > this.fileSize) { System.Diagnostics.Debug.WriteLine("current block largher than file size: " + currentBlockSize); return(null); } // seek to the current block in the map file this.inputFile.Seek(subFileParameter.StartAddress + currentBlockpointer, SeekOrigin.Begin); // read the current block into the buffer if (!this.readBuffer.ReadFromFile(currentBlockSize)) { // skip the current block System.Diagnostics.Debug.WriteLine("reading current block has failed: " + currentBlockSize); return(null); } // calculate the top-left coordinates of the underlying tile this.tile = new Tile( subFileParameter.BoundaryTileLeft + column, subFileParameter.BoundaryTileTop + row, subFileParameter.BaseZoomLevel, Projection.TileSize ); this.tilePosition = Projection.MappointToGeoPoint(tile.MapPoint1); try { NodeWayBundle nodeWayBundle = ProcessBlock(queryParameters, subFileParameter); mapReadResultBuilder.Add(nodeWayBundle); } catch (IndexOutOfRangeException e) { System.Diagnostics.Debug.WriteLine(e.Message); } } } // the query is finished, was the water flag set for all blocks? if (queryIsWater && queryReadWaterInfo) { mapReadResultBuilder.isWater = true; } return(mapReadResultBuilder.build()); }