/** * 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.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 ncaches; private int indexsize; public OsmFile( PhysicalFile rafile, int lonDegree, int latDegree, DataBuffers dataBuffers ) throws Exception { 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; cellsize = 1000000 / divisor; 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 ) throws Exception { int lonIdx = ilon / cellsize; int latIdx = ilat / cellsize; MicroCache segment = createMicroCache( lonIdx, latIdx, dataBuffers, wayValidator, waypointMatcher, true ); 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 Exception { 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 ) throws Exception { 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 ); dataBuffers = new DataBuffers( ab ); } // hack: the checksum contains the information // which type of microcache we have 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 ) { return reallyDecode ? new MicroCache2( dataBuffers, lonIdx, latIdx, divisor, wayValidator, waypointMatcher ) : null; } 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 cleanNonVirgin() { 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 ) { microCaches[i] = null; } } } }