diff options
| author | George Hazan <ghazan@miranda.im> | 2018-01-26 17:38:31 +0300 | 
|---|---|---|
| committer | George Hazan <ghazan@miranda.im> | 2018-01-26 17:38:31 +0300 | 
| commit | dea9c030340e50324eba97c72a27c151bed12e1c (patch) | |
| tree | 6fc156f40f52a9fc6e6b29e60001959477ee1a5e /libs/freeimage/src/FreeImage/CacheFile.cpp | |
| parent | c6e8f8223cab9d799593b7b2cfa22134aa9745d6 (diff) | |
AdvaImg:
- freeimage extracted to the separate library;
- FI_INTERFACE removed, all references to it are replaced with direct calls of FreeImage_* functions;
- unified project for AdvaImg
Diffstat (limited to 'libs/freeimage/src/FreeImage/CacheFile.cpp')
| -rw-r--r-- | libs/freeimage/src/FreeImage/CacheFile.cpp | 271 | 
1 files changed, 271 insertions, 0 deletions
diff --git a/libs/freeimage/src/FreeImage/CacheFile.cpp b/libs/freeimage/src/FreeImage/CacheFile.cpp new file mode 100644 index 0000000000..086393bf03 --- /dev/null +++ b/libs/freeimage/src/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 "../stdafx.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); +} +  | 
