#include <sys/types.h>
#include <sys/stat.h>

#include <fcntl.h>

#include "stream.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "sys-mmap.h"
#include "sys-files.h"

#ifndef O_BINARY
# define O_BINARY 0
#endif

int stream_open(stream *f, buffer *fn) {
	struct stat st;
#ifdef HAVE_MMAP
	int fd;
#elif defined _WIN32
	HANDLE *fh, *mh;
	void *p;
#endif

	f->start = NULL;

	if (-1 == stat(fn->ptr, &st)) {
		return -1;
	}

	f->size = st.st_size;

#ifdef HAVE_MMAP
	if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
		return -1;
	}

	f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);

	close(fd);

	if (MAP_FAILED == f->start) {
		return -1;
	}

#elif defined _WIN32
	fh = CreateFile(fn->ptr,
			GENERIC_READ,
			FILE_SHARE_READ,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_READONLY,
			NULL);

	if (fh == INVALID_HANDLE_VALUE) return -1;

	mh = CreateFileMapping( fh,
			NULL,
			PAGE_READONLY,
			(sizeof(off_t) > 4) ? f->size >> 32 : 0,
			f->size & 0xffffffff,
			NULL);

	if (!mh) {
		LPVOID lpMsgBuf;
		FormatMessage(
		        FORMAT_MESSAGE_ALLOCATE_BUFFER |
		        FORMAT_MESSAGE_FROM_SYSTEM,
		        NULL,
		        GetLastError(),
		        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		        (LPTSTR) &lpMsgBuf,
		        0, NULL );

		return -1;
	}

	p = MapViewOfFile(mh,
			FILE_MAP_READ,
			0,
			0,
			0);
	CloseHandle(mh);
	CloseHandle(fh);

	f->start = p;
#else
# error no mmap found
#endif

	return 0;
}

int stream_close(stream *f) {
#ifdef HAVE_MMAP
	if (f->start) munmap(f->start, f->size);
#elif defined(__WIN32)
	if (f->start) UnmapViewOfFile(f->start);
#endif

	f->start = NULL;

	return 0;
}
