1/* -*- c -*-
2 * File: loadfile.h
3 * Author: Igor Vlasenko <vlasenko@imath.kiev.ua>
4 * Created: Thu Sep  8 17:16:48 2005
5 *
6 * $Id$
7 */
8
9#ifdef HAVE_CONFIG_H
10#include "config.h"
11#endif
12
13#ifdef USE_MMAP
14
15#ifdef WIN32
16/*
17 * the win32 code of Viacheslav Sheveliov <slavash@aha.ru>
18 * viy: should work for win64 too.
19 */
20
21#include <windows.h>
22#include <stdio.h>
23
24static PSTRING mmap_load_file(const char *filepath) {
25        PSTRING memarea = { NULL, NULL };
26        HANDLE hFile, hMapObject = NULL;
27
28        hFile = CreateFile(
29                TEXT(filepath),
30                GENERIC_READ,
31                FILE_SHARE_READ,
32                NULL,
33                OPEN_EXISTING,
34                FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
35                NULL
36        );
37
38        if (hFile != INVALID_HANDLE_VALUE) {
39                hMapObject = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
40
41                if (hMapObject) {
42                        // Get a pointer to the file-mapped shared memory.
43                        LPCTSTR lpvMem = (LPTSTR) MapViewOfFile(hMapObject, FILE_MAP_READ, 0, 0, 0);
44
45                        if (lpvMem) {
46                                // Everything OK!
47
48                                memarea.begin = (char *) lpvMem;
49                                memarea.endnext = memarea.begin + GetFileSize(hFile, NULL);
50                                // After MapViewOfFile we don't need file handles no more.
51                                // Undocumented, but it works! (In read-only mode?)
52                                CloseHandle(hMapObject);
53                                CloseHandle(hFile);
54
55                                return memarea;
56
57                        }
58                }
59        }
60
61        // Something goes wrong
62
63        {
64                // Save last error code, before any system call
65                DWORD dwLastError = GetLastError();
66
67                // Report error, if file size != 0
68                // Mapping of zero-length file cause CreateFileMapping to fail.
69                // So skip error messages in this case.
70                if (hFile == INVALID_HANDLE_VALUE && GetFileSize(hFile, NULL) != 0)
71                        fprintf(stderr, "Could not open file '%s'. (system error#%ld)\n", filepath, dwLastError);
72
73        }
74        // Close all opened handles
75        if (hMapObject) CloseHandle(hMapObject);
76        if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
77
78        return memarea;
79}
80
81/* we use function, not define, because someday we may need its address */
82static int mmap_unload_file(PSTRING memarea) { return UnmapViewOfFile((void*) memarea.begin) ? 0 : -1; };
83/* define mmap_unload_file(map) (UnmapViewOfFile((LPCVOID) map.begin) ? 0 : -1) */
84
85#else /* unix, sweet unix :) */
86#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_SYS_STAT_H)
87
88/* # define NULL 0 */
89#include <sys/stat.h>
90#include <sys/mman.h>
91#include <fcntl.h>  /* open  */
92#include <unistd.h> /* close */
93
94static
95PSTRING
96mmap_load_file (const char* filepath) {
97  int fd;
98  struct stat st;
99  size_t size_in_bytes;
100  PSTRING memarea={NULL,NULL};
101  fd = open(filepath, O_RDONLY);
102  if (fd == -1) return memarea; /* {NULL,NULL} */
103  fstat(fd, &st);
104  size_in_bytes = st.st_size;
105  /* mmap size_in_bytes+1 to avoid crash with empty file */
106  memarea.begin = (char *) mmap(0, size_in_bytes+1,  PROT_READ,  MAP_SHARED, fd, 0);
107  close(fd);
108  memarea.endnext=memarea.begin+size_in_bytes;
109  return memarea;
110}
111
112static
113int
114mmap_unload_file (PSTRING memarea) {
115  /* destroying */
116  return munmap((void *)memarea.begin, memarea.endnext-memarea.begin);
117}
118
119#endif /* UNIX */
120#endif /* WIN32 */
121
122#else
123/*
124 * system seems to have no mmap ;
125 * we use standard C buffered read
126 */
127#include <stdio.h>
128static
129PSTRING
130mmap_load_file (const char* filepath) {
131  FILE *stream;
132  size_t size_in_bytes=0;
133  size_t realsize;
134  size_t chunksize=4096;
135  size_t memsize=chunksize;
136  PSTRING memarea={NULL,NULL};
137  char* writepoint;
138  /* text mode for HTML::Template compatibility */
139  stream = fopen(filepath, "r");
140  if (stream == NULL) return memarea; /* {NULL,NULL} */
141  /* mmap size_in_bytes+1 to avoid crash with empty file */
142  memarea.begin=(const char*) malloc(memsize+1);
143  writepoint=(char*)memarea.begin;
144
145  while (1) {
146    realsize=fread(writepoint, 1, chunksize, stream);
147    size_in_bytes+=realsize;
148    if (realsize==chunksize) {
149      writepoint+=chunksize;
150      if (size_in_bytes+chunksize>memsize) {
151	memsize*=2;
152	memarea.begin=(char*) realloc((char*)memarea.begin, memsize+1);
153	writepoint=((char*)memarea.begin)+size_in_bytes;
154      }
155    } else {
156      fclose(stream);
157      memarea.endnext=memarea.begin+size_in_bytes;
158      return memarea;
159    }
160  }
161}
162
163static
164int
165mmap_unload_file (PSTRING memarea) {
166  /* destroying */
167  free((char*)memarea.begin);
168  return 0;
169}
170
171#endif /* USE_MMAP */
172