/** * cache for a single square * * @author ab */ package btools.mapaccess; import java.io.IOException; import java.io.RandomAccessFile; import btools.codec.DataBuffers; import btools.codec.MicroCache; import btools.codec.MicroCache2; import btools.codec.StatCoderContext; import btools.codec.TagValueValidator; import btools.codec.WaypointMatcher; import btools.util.ByteDataReader; import btools.util.Crc32; final class OsmFile { private RandomAccessFile is = null; private long fileOffset; private int[] posIdx; private MicroCache[] microCaches; public int lonDegree; public int latDegree; public String filename; private int divisor; private int cellsize; private int indexsize; protected byte elevationType = 3; public OsmFile(PhysicalFile rafile, int lonDegree, int latDegree, DataBuffers dataBuffers) throws IOException { this.lonDegree = lonDegree; this.latDegree = latDegree; int lonMod5 = lonDegree % 5; int latMod5 = latDegree % 5; int tileIndex = lonMod5 * 5 + latMod5; if (rafile != null) { divisor = rafile.divisor; elevationType = rafile.elevationType; cellsize = 1000000 / divisor; int ncaches = divisor * divisor; indexsize = ncaches * 4; byte[] iobuffer = dataBuffers.iobuffer; filename = rafile.fileName; long[] index = rafile.fileIndex; fileOffset = tileIndex > 0 ? index[tileIndex - 1] : 200L; if (fileOffset == index[tileIndex]) return; // empty is = rafile.ra; posIdx = new int[ncaches]; microCaches = new MicroCache[ncaches]; is.seek(fileOffset); is.readFully(iobuffer, 0, indexsize); if (rafile.fileHeaderCrcs != null) { int headerCrc = Crc32.crc(iobuffer, 0, indexsize); if (rafile.fileHeaderCrcs[tileIndex] != headerCrc) { throw new IOException("sub index checksum error"); } } ByteDataReader dis = new ByteDataReader(iobuffer); for (int i = 0; i < ncaches; i++) { posIdx[i] = dis.readInt(); } } } public boolean hasData() { return microCaches != null; } public MicroCache getMicroCache(int ilon, int ilat) { int lonIdx = ilon / cellsize; int latIdx = ilat / cellsize; int subIdx = (latIdx - divisor * latDegree) * divisor + (lonIdx - divisor * lonDegree); return microCaches[subIdx]; } public MicroCache createMicroCache(int ilon, int ilat, DataBuffers dataBuffers, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, OsmNodesMap hollowNodes) throws Exception { int lonIdx = ilon / cellsize; int latIdx = ilat / cellsize; MicroCache segment = createMicroCache(lonIdx, latIdx, dataBuffers, wayValidator, waypointMatcher, true, hollowNodes); int subIdx = (latIdx - divisor * latDegree) * divisor + (lonIdx - divisor * lonDegree); microCaches[subIdx] = segment; return segment; } private int getPosIdx(int idx) { return idx == -1 ? indexsize : posIdx[idx]; } public int getDataInputForSubIdx(int subIdx, byte[] iobuffer) throws IOException { int startPos = getPosIdx(subIdx - 1); int endPos = getPosIdx(subIdx); int size = endPos - startPos; if (size > 0) { is.seek(fileOffset + startPos); if (size <= iobuffer.length) { is.readFully(iobuffer, 0, size); } } return size; } public MicroCache createMicroCache(int lonIdx, int latIdx, DataBuffers dataBuffers, TagValueValidator wayValidator, WaypointMatcher waypointMatcher, boolean reallyDecode, OsmNodesMap hollowNodes) throws IOException { int subIdx = (latIdx - divisor * latDegree) * divisor + (lonIdx - divisor * lonDegree); byte[] ab = dataBuffers.iobuffer; int asize = getDataInputForSubIdx(subIdx, ab); if (asize == 0) { return MicroCache.emptyCache(); } if (asize > ab.length) { ab = new byte[asize]; asize = getDataInputForSubIdx(subIdx, ab); } StatCoderContext bc = new StatCoderContext(ab); try { if (!reallyDecode) { return null; } if (hollowNodes == null) { return new MicroCache2(bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher); } new DirectWeaver(bc, dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher, hollowNodes); return MicroCache.emptyNonVirgin; } finally { // crc check only if the buffer has not been fully read int readBytes = (bc.getReadingBitPosition() + 7) >> 3; if (readBytes != asize - 4) { int crcData = Crc32.crc(ab, 0, asize - 4); int crcFooter = new ByteDataReader(ab, asize - 4).readInt(); if (crcData == crcFooter) { throw new IOException("old, unsupported data-format"); } else if ((crcData ^ 2) != crcFooter) { throw new IOException("checkum error"); } } } } // set this OsmFile to ghost-state: long setGhostState() { long sum = 0; int nc = microCaches == null ? 0 : microCaches.length; for (int i = 0; i < nc; i++) { MicroCache mc = microCaches[i]; if (mc == null) continue; if (mc.virgin) { mc.ghost = true; sum += mc.getDataSize(); } else { microCaches[i] = null; } } return sum; } long collectAll() { long deleted = 0; int nc = microCaches == null ? 0 : microCaches.length; for (int i = 0; i < nc; i++) { MicroCache mc = microCaches[i]; if (mc == null) continue; if (!mc.ghost) { deleted += mc.collect(0); } } return deleted; } long cleanGhosts() { long deleted = 0; int nc = microCaches == null ? 0 : microCaches.length; for (int i = 0; i < nc; i++) { MicroCache mc = microCaches[i]; if (mc == null) continue; if (mc.ghost) { microCaches[i] = null; } } return deleted; } void clean(boolean all) { int nc = microCaches == null ? 0 : microCaches.length; for (int i = 0; i < nc; i++) { MicroCache mc = microCaches[i]; if (mc == null) continue; if (all || !mc.virgin) { microCaches[i] = null; } } } }