/** * Copyright (c) 2005-2017, KoLmafia development team * http://kolmafia.sourceforge.net/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * [1] Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * [2] Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * [3] Neither the name "KoLmafia" nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package net.sourceforge.kolmafia.textui; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import net.java.dev.spellcast.utilities.DataUtilities; import net.sourceforge.kolmafia.KoLConstants; import net.sourceforge.kolmafia.KoLmafia; import net.sourceforge.kolmafia.textui.parsetree.Value; import net.sourceforge.kolmafia.utilities.ByteBufferUtilities; import net.sourceforge.kolmafia.utilities.RollingLinkedList; public class DataFileCache { private static final RollingLinkedList recentlyUsedList = new RollingLinkedList( 500 ); private static final Map<String, Long> dataFileTimestampCache = new HashMap<String, Long>(); private static final Map<String, byte[]> dataFileDataCache = new HashMap<String, byte[]>(); public static void clearCache() { DataFileCache.recentlyUsedList.clear(); DataFileCache.dataFileTimestampCache.clear(); DataFileCache.dataFileDataCache.clear(); } public static File getFile( String filename, boolean readOnly ) { if ( filename.startsWith( "http://" ) ) { return null; } filename = filename.substring( filename.lastIndexOf( "\\" ) + 1 ); File[] parents; if ( !readOnly && filename.endsWith( ".ash" ) ) { parents = new File[] { KoLConstants.DATA_LOCATION }; } else { parents = new File[] { KoLConstants.SCRIPT_LOCATION, KoLConstants.RELAY_LOCATION, KoLConstants.DATA_LOCATION, }; } for ( int i = 0; i < parents.length; ++i ) { File file = new File( parents[ i ], filename ); if ( checkFile( parents, file, true ) ) { try { if ( file.getCanonicalPath().startsWith( parents[ i ].getCanonicalPath() ) ) { return file; } else { KoLmafia.updateDisplay( KoLConstants.MafiaState.ERROR, filename + " is not within KoLmafia's directories." ); return null; } } catch ( IOException e ) { return null; } } } File file = new File( KoLConstants.ROOT_LOCATION, filename ); if ( file.exists() && file.getParent().equals( KoLConstants.ROOT_LOCATION.getAbsolutePath() ) ) { return file; } file = new File( KoLConstants.DATA_LOCATION, filename ); try { if ( file.getCanonicalPath().startsWith( KoLConstants.DATA_LOCATION.getCanonicalPath() ) ) { return file; } } catch ( IOException e ) { return null; } KoLmafia.updateDisplay( KoLConstants.MafiaState.ERROR, filename + " is not within KoLmafia's directories." ); return null; } private static boolean checkFile( File[] parents, File file, boolean checkExists ) { if ( checkExists && !file.exists() ) { return false; } file = file.getAbsoluteFile(); try { File settings = KoLConstants.SETTINGS_LOCATION.getCanonicalFile(); if ( settings.equals( file.getCanonicalFile().getParentFile() ) ) { return false; } while ( file != null ) { for ( int i = 0; i < parents.length; ++i ) { if ( file.equals( parents[ i ] ) ) { return true; } } file = file.getParentFile(); } } catch ( Exception e ) { } return false; } public static BufferedReader getReader( final String filename ) { if ( filename.startsWith( "http://" ) ) { return DataUtilities.getReader( "", filename ); } byte[] data = DataFileCache.getBytes( filename ); return DataUtilities.getReader( new ByteArrayInputStream( data ) ); } public static byte[] getBytes( final String filename ) { File input = DataFileCache.getFile( filename, true ); if ( input == null ) { return new byte[0]; } long modifiedTime = input.lastModified(); Long cacheModifiedTime = dataFileTimestampCache.get( filename ); if ( cacheModifiedTime != null && cacheModifiedTime.longValue() == modifiedTime ) { return (byte[]) dataFileDataCache.get( filename ); } InputStream istream = null; if ( input.exists() ) { try { istream = new FileInputStream( input ); } catch ( IOException e ) { } } if ( istream == null ) { istream = DataUtilities.getInputStream( "data", filename ); if ( istream instanceof ByteArrayInputStream ) { istream = DataUtilities.getInputStream( "", filename ); } } byte[] data = ByteBufferUtilities.read( istream ); DataFileCache.updateCache( filename, modifiedTime, data ); return data; } public static Value printBytes( final String filename, final byte[] data ) { File output = DataFileCache.getFile( filename, false ); if ( output == null ) { return DataTypes.FALSE_VALUE; } if ( !output.exists() ) { try { File parent = output.getParentFile(); if ( parent != null ) { parent.mkdirs(); } output.createNewFile(); } catch ( Exception e ) { return DataTypes.FALSE_VALUE; } } try { FileOutputStream ostream = new FileOutputStream( output, false ); ostream.write( data ); ostream.close(); } catch ( Exception e ) { return DataTypes.FALSE_VALUE; } DataFileCache.updateCache( filename, output.lastModified(), data ); return DataTypes.TRUE_VALUE; } private static void updateCache( String filename, long modifiedTime, byte[] data ) { Object recentlyUsedCheck = DataFileCache.recentlyUsedList.update( filename ); if ( recentlyUsedCheck != null ) { DataFileCache.dataFileTimestampCache.remove( filename ); DataFileCache.dataFileDataCache.remove( filename ); } DataFileCache.dataFileTimestampCache.put( filename, new Long( modifiedTime ) ); DataFileCache.dataFileDataCache.put( filename, data ); } }