/*
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License version 2 
	as published by the Free Software Foundation.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


	Copyright (C) 2006  Thierry Berger-Perrin <tbptbp@gmail.com>
*/
#include "specifics.h"
#include "sys_map.h"

#include "sys_log.h"

#ifdef LINUX
	#include <cstdio>		// perror
	#include <sys/types.h>
	#include <sys/stat.h>	// open/close
	#include <fcntl.h>
	#include <unistd.h>		// lseek
	#include <sys/mman.h>
#endif

namespace sys {
	#ifdef WINDOWS
		void map_t::cleanup() {
				//syslog("unmapping.\n");
				UnmapViewOfFile(start);
				CloseHandle(mapping);
				CloseHandle(file);
				file = 0; mapping = 0; start = 0; stop = 0; size = 0;
				mapped = false;
			}

		bool_t map_t::open(const char *path) {
			//syslog("sys::map_t::open: mapping '%s'.\n",path
			void *data = 0;
			file = 0; mapping = 0; start = 0; stop = 0; size = 0;
			DWORD hints = 0;

			file = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, hints, 0);
			if (file != INVALID_HANDLE_VALUE) {
				mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
				if (mapping != 0) {
					data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
					if (data != 0) {
						size = GetFileSize(file, 0);
						if (size != INVALID_FILE_SIZE) {
							start	= data;
							stop	= ((char*)data) + size;
							//syslog("sys::map_t::open: mapped %.3f M @ 0x%p.\n", float(size)/(1024.f*1024), start);
							mapped = true;
							return true;
						}
						else sys::log("sys::map_t::open: GetFileSize failed for '%s'.\n",path);
					}
					else sys::log("sys::map_t::open: MapViewOfFile failed for '%s'.\n",path);
				}
				else sys::log("sys::map_t::open: CreateFileMapping failed for '%s'.\n",path);
			}
			else sys::log("sys::map_t::open: CreateFile failed for '%s'.\n",path);

			cleanup();
			return false;
		}
	#else
		void map_t::cleanup() {
			if (mapped) {
				munmap(start, size);

				start = stop = 0;
				size = 0;
				mapped = false;
			}

			if (fd) {
				::close(fd);
				fd = 0;
			}
		}


		bool_t map_t::open(const char *path) {
			fd = ::open(path, O_RDONLY);
			if (fd <= 0) {
				perror("sys::map_t::open: failed to open file -- ");
				return false;
			}
			size = lseek(fd, 0, SEEK_END);
			lseek(fd, 0, SEEK_SET);
			//start = mmap(0, size, PROT_READ | (writeable ? PROT_WRITE : 0), MAP_SHARED, fildes, 0);
			start = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
			if (start <= 0) {
				perror("sys::map_t::open: failed to map -- ");
				return false;
			}

			stop = ((char *) start) + size;

			sys::log("sys::map_t: mapped '%s' @ 0x%p, %d bytes.\n", path, start, size);

			mapped = true;
			return true;
		}
	#endif
}
