diff options
Diffstat (limited to 'plugins/FreeImage/Source/FreeImage/CacheFile.cpp')
| -rw-r--r-- | plugins/FreeImage/Source/FreeImage/CacheFile.cpp | 271 | 
1 files changed, 271 insertions, 0 deletions
diff --git a/plugins/FreeImage/Source/FreeImage/CacheFile.cpp b/plugins/FreeImage/Source/FreeImage/CacheFile.cpp new file mode 100644 index 0000000000..fc1ba0d798 --- /dev/null +++ b/plugins/FreeImage/Source/FreeImage/CacheFile.cpp @@ -0,0 +1,271 @@ +// ==========================================================
 +// Multi-Page functions
 +//
 +// Design and implementation by
 +// - Floris van den Berg (flvdberg@wxs.nl)
 +// - checkered (checkered@users.sourceforge.net)
 +//
 +// This file is part of FreeImage 3
 +//
 +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 +// THIS DISCLAIMER.
 +//
 +// Use at your own risk!
 +// ==========================================================
 +
 +#ifdef _MSC_VER 
 +#pragma warning (disable : 4786) // identifier was truncated to 'number' characters
 +#endif 
 +
 +#include "CacheFile.h"
 +
 +// ----------------------------------------------------------
 +
 +CacheFile::CacheFile(const std::string filename, BOOL keep_in_memory) :
 +m_file(NULL),
 +m_filename(filename),
 +m_free_pages(),
 +m_page_cache_mem(),
 +m_page_cache_disk(),
 +m_page_map(),
 +m_page_count(0),
 +m_current_block(NULL),
 +m_keep_in_memory(keep_in_memory) {
 +}
 +
 +CacheFile::~CacheFile() {
 +}
 +
 +BOOL
 +CacheFile::open() {
 +	if ((!m_filename.empty()) && (!m_keep_in_memory)) {
 +		m_file = fopen(m_filename.c_str(), "w+b");
 +		return (m_file != NULL);
 +	}
 +
 +	return (m_keep_in_memory == TRUE);
 +}
 +
 +void
 +CacheFile::close() {
 +	// dispose the cache entries
 +
 +	while (!m_page_cache_disk.empty()) {
 +		Block *block = *m_page_cache_disk.begin();
 +		m_page_cache_disk.pop_front();
 +		delete [] block->data;
 +		delete block;
 +	}
 +	while (!m_page_cache_mem.empty()) { 
 +		Block *block = *m_page_cache_mem.begin(); 
 +		m_page_cache_mem.pop_front(); 
 +		delete [] block->data; 
 +		delete block; 
 +	} 
 +
 +	if (m_file) {
 +		// close the file
 +
 +		fclose(m_file);
 +
 +		// delete the file
 +
 +		remove(m_filename.c_str());
 +	}
 +}
 +
 +void
 +CacheFile::cleanupMemCache() {
 +	if (!m_keep_in_memory) {
 +		if (m_page_cache_mem.size() > CACHE_SIZE) {
 +			// flush the least used block to file
 +
 +			Block *old_block = m_page_cache_mem.back();
 +			fseek(m_file, old_block->nr * BLOCK_SIZE, SEEK_SET);
 +			fwrite(old_block->data, BLOCK_SIZE, 1, m_file);
 +
 +			// remove the data
 +
 +			delete [] old_block->data;
 +			old_block->data = NULL;
 +
 +			// move the block to another list
 +
 +			m_page_cache_disk.splice(m_page_cache_disk.begin(), m_page_cache_mem, --m_page_cache_mem.end());
 +			m_page_map[old_block->nr] = m_page_cache_disk.begin();
 +		}
 +	}
 +}
 +
 +int
 +CacheFile::allocateBlock() {
 +	Block *block = new Block;
 +	block->data = new BYTE[BLOCK_SIZE];
 +	block->next = 0;
 +
 +	if (!m_free_pages.empty()) {
 +		block->nr = *m_free_pages.begin();
 +		m_free_pages.pop_front();
 +	} else {
 +		block->nr = m_page_count++;
 +	}
 +
 +	m_page_cache_mem.push_front(block);
 +	m_page_map[block->nr] = m_page_cache_mem.begin();
 +
 +	cleanupMemCache();
 +
 +	return block->nr;
 +}
 +
 +Block *
 +CacheFile::lockBlock(int nr) {
 +	if (m_current_block == NULL) {
 +		PageMapIt it = m_page_map.find(nr);
 +
 +		if (it != m_page_map.end()) {
 +			m_current_block = *(it->second);
 +
 +			// the block is swapped out to disc. load it back
 +			// and remove the block from the cache. it might get cached
 +			// again as soon as the memory buffer fills up
 +
 +			if (m_current_block->data == NULL) {
 +				m_current_block->data = new BYTE[BLOCK_SIZE];
 +
 +				fseek(m_file, m_current_block->nr * BLOCK_SIZE, SEEK_SET);
 +				fread(m_current_block->data, BLOCK_SIZE, 1, m_file);
 +
 +				m_page_cache_mem.splice(m_page_cache_mem.begin(), m_page_cache_disk, it->second);
 +				m_page_map[nr] = m_page_cache_mem.begin();
 +			}
 +
 +			// if the memory cache size is too large, swap an item to disc
 +
 +			cleanupMemCache();
 +
 +			// return the current block
 +
 +			return m_current_block;
 +		}
 +	}
 +
 +	return NULL;
 +}
 +
 +BOOL
 +CacheFile::unlockBlock(int nr) {
 +	if (m_current_block) {
 +		m_current_block = NULL;
 +
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +BOOL
 +CacheFile::deleteBlock(int nr) {
 +	if (!m_current_block) {
 +		PageMapIt it = m_page_map.find(nr);
 +
 +		// remove block from cache
 +
 +		if (it != m_page_map.end())
 +			m_page_map.erase(nr);
 +
 +		// add block to free page list
 +
 +		m_free_pages.push_back(nr);
 +
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +BOOL
 +CacheFile::readFile(BYTE *data, int nr, int size) {
 +	if ((data) && (size > 0)) {
 +		int s = 0;
 +		int block_nr = nr;
 +
 +		do {
 +			int copy_nr = block_nr;
 +
 +			Block *block = lockBlock(copy_nr);
 +
 +			block_nr = block->next;
 +
 +			memcpy(data + s, block->data, (s + BLOCK_SIZE > size) ? size - s : BLOCK_SIZE);
 +
 +			unlockBlock(copy_nr);
 +
 +			s += BLOCK_SIZE;
 +		} while (block_nr != 0);
 +
 +		return TRUE;
 +	}
 +
 +	return FALSE;
 +}
 +
 +int
 +CacheFile::writeFile(BYTE *data, int size) {
 +	if ((data) && (size > 0)) {
 +		int nr_blocks_required = 1 + (size / BLOCK_SIZE);
 +		int count = 0;
 +		int s = 0;
 +		int stored_alloc;
 +		int alloc;
 +		
 +		stored_alloc = alloc = allocateBlock();
 +
 +		do {
 +			int copy_alloc = alloc;
 +
 +			Block *block = lockBlock(copy_alloc);
 +
 +			block->next = 0;
 +
 +			memcpy(block->data, data + s, (s + BLOCK_SIZE > size) ? size - s : BLOCK_SIZE);
 +
 +			if (count + 1 < nr_blocks_required)
 +				alloc = block->next = allocateBlock();
 +
 +			unlockBlock(copy_alloc);
 +
 +			s += BLOCK_SIZE;			
 +		} while (++count < nr_blocks_required);
 +
 +		return stored_alloc;
 +	}
 +
 +	return 0;
 +}
 +
 +void
 +CacheFile::deleteFile(int nr) {
 +	do {
 +		Block *block = lockBlock(nr);
 +
 +		if (block == NULL)
 +			break;
 +
 +		int next = block->next;
 +
 +		unlockBlock(nr);
 +
 +		deleteBlock(nr);
 +
 +		nr = next;
 +	} while (nr != 0);
 +}
 +
  | 
