1 /* Interface to mmap style I/O
2
3 (c) 2006-2008 (W3C) MIT, ERCIM, Keio University
4 See tidy.h for the copyright notice.
5
6 Originally contributed by Cory Nelson and Nuno Lopes
7
8 $Id: mappedio.c,v 1.14 2008/03/18 20:19:35 arnaud02 Exp $
9 */
10
11 /* keep these here to keep file non-empty */
12 #include "forward.h"
13 #include "mappedio.h"
14
15 #if SUPPORT_POSIX_MAPPED_FILES
16
17 #include "fileio.h"
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <stdio.h>
23
24 #include <sys/mman.h>
25
26
27 typedef struct
28 {
29 TidyAllocator *allocator;
30 const byte *base;
31 size_t pos, size;
32 } MappedFileSource;
33
mapped_getByte(void * sourceData)34 static int TIDY_CALL mapped_getByte( void* sourceData )
35 {
36 MappedFileSource* fin = (MappedFileSource*) sourceData;
37 return fin->base[fin->pos++];
38 }
39
mapped_eof(void * sourceData)40 static Bool TIDY_CALL mapped_eof( void* sourceData )
41 {
42 MappedFileSource* fin = (MappedFileSource*) sourceData;
43 return (fin->pos >= fin->size);
44 }
45
mapped_ungetByte(void * sourceData,byte ARG_UNUSED (bv))46 static void TIDY_CALL mapped_ungetByte( void* sourceData, byte ARG_UNUSED(bv) )
47 {
48 MappedFileSource* fin = (MappedFileSource*) sourceData;
49 fin->pos--;
50 }
51
TY_(initFileSource)52 int TY_(initFileSource)( TidyAllocator *allocator, TidyInputSource* inp, FILE* fp )
53 {
54 MappedFileSource* fin;
55 struct stat sbuf;
56 int fd;
57
58 fin = (MappedFileSource*) TidyAlloc( allocator, sizeof(MappedFileSource) );
59 if ( !fin )
60 return -1;
61
62 fd = fileno(fp);
63 if ( fstat(fd, &sbuf) == -1
64 || sbuf.st_size == 0
65 || (fin->base = mmap(0, fin->size = sbuf.st_size, PROT_READ,
66 MAP_SHARED, fd, 0)) == MAP_FAILED)
67 {
68 TidyFree( allocator, fin );
69 /* Fallback on standard I/O */
70 return TY_(initStdIOFileSource)( allocator, inp, fp );
71 }
72
73 fin->pos = 0;
74 fin->allocator = allocator;
75 fclose(fp);
76
77 inp->getByte = mapped_getByte;
78 inp->eof = mapped_eof;
79 inp->ungetByte = mapped_ungetByte;
80 inp->sourceData = fin;
81
82 return 0;
83 }
84
TY_(freeFileSource)85 void TY_(freeFileSource)( TidyInputSource* inp, Bool closeIt )
86 {
87 if ( inp->getByte == mapped_getByte )
88 {
89 MappedFileSource* fin = (MappedFileSource*) inp->sourceData;
90 munmap( (void*)fin->base, fin->size );
91 TidyFree( fin->allocator, fin );
92 }
93 else
94 TY_(freeStdIOFileSource)( inp, closeIt );
95 }
96
97 #endif
98
99
100 #if defined(_WIN32)
101 #include "streamio.h"
102 #include "tidy-int.h"
103 #include "message.h"
104
105 #include <errno.h>
106 #if _MSC_VER < 1300 /* less than msvc++ 7.0 */
107 #pragma warning(disable:4115) /* named type definition in parentheses in windows headers */
108 #endif
109 #include <windows.h>
110
111 typedef struct _fp_input_mapped_source
112 {
113 TidyAllocator *allocator;
114 LONGLONG size, pos;
115 HANDLE file, map;
116 byte *view, *iter, *end;
117 unsigned int gran;
118 } MappedFileSource;
119
mapped_openView(MappedFileSource * data)120 static int mapped_openView( MappedFileSource *data )
121 {
122 DWORD numb = ( ( data->size - data->pos ) > data->gran ) ?
123 data->gran : (DWORD)( data->size - data->pos );
124
125 if ( data->view )
126 {
127 UnmapViewOfFile( data->view );
128 data->view = NULL;
129 }
130
131 data->view = MapViewOfFile( data->map, FILE_MAP_READ,
132 (DWORD)( data->pos >> 32 ),
133 (DWORD)data->pos, numb );
134
135 if ( !data->view ) return -1;
136
137 data->iter = data->view;
138 data->end = data->iter + numb;
139
140 return 0;
141 }
142
mapped_getByte(void * sourceData)143 static int TIDY_CALL mapped_getByte( void *sourceData )
144 {
145 MappedFileSource *data = sourceData;
146
147 if ( !data->view || data->iter >= data->end )
148 {
149 data->pos += data->gran;
150
151 if ( data->pos >= data->size || mapped_openView(data) != 0 )
152 return EndOfStream;
153 }
154
155 return *( data->iter++ );
156 }
157
mapped_eof(void * sourceData)158 static Bool TIDY_CALL mapped_eof( void *sourceData )
159 {
160 MappedFileSource *data = sourceData;
161 return ( data->pos >= data->size );
162 }
163
mapped_ungetByte(void * sourceData,byte ARG_UNUSED (bt))164 static void TIDY_CALL mapped_ungetByte( void *sourceData, byte ARG_UNUSED(bt) )
165 {
166 MappedFileSource *data = sourceData;
167
168 if ( data->iter >= data->view )
169 {
170 --data->iter;
171 return;
172 }
173
174 if ( data->pos < data->gran )
175 {
176 assert(0);
177 return;
178 }
179
180 data->pos -= data->gran;
181 mapped_openView( data );
182 }
183
initMappedFileSource(TidyAllocator * allocator,TidyInputSource * inp,HANDLE fp)184 static int initMappedFileSource( TidyAllocator *allocator, TidyInputSource* inp, HANDLE fp )
185 {
186 MappedFileSource* fin = NULL;
187
188 inp->getByte = mapped_getByte;
189 inp->eof = mapped_eof;
190 inp->ungetByte = mapped_ungetByte;
191
192 fin = (MappedFileSource*) TidyAlloc( allocator, sizeof(MappedFileSource) );
193 if ( !fin )
194 return -1;
195
196 #if _MSC_VER < 1300 /* less than msvc++ 7.0 */
197 {
198 LARGE_INTEGER* pli = (LARGE_INTEGER *)&fin->size;
199 (DWORD)pli->LowPart = GetFileSize( fp, (DWORD *)&pli->HighPart );
200 if ( GetLastError() != NO_ERROR || fin->size <= 0 )
201 {
202 TidyFree(allocator, fin);
203 return -1;
204 }
205 }
206 #else
207 if ( !GetFileSizeEx( fp, (LARGE_INTEGER*)&fin->size )
208 || fin->size <= 0 )
209 {
210 TidyFree(allocator, fin);
211 return -1;
212 }
213 #endif
214
215 fin->map = CreateFileMapping( fp, NULL, PAGE_READONLY, 0, 0, NULL );
216
217 if ( !fin->map )
218 {
219 TidyFree(allocator, fin);
220 return -1;
221 }
222
223 {
224 SYSTEM_INFO info;
225 GetSystemInfo( &info );
226 fin->gran = info.dwAllocationGranularity;
227 }
228
229 fin->allocator = allocator;
230 fin->pos = 0;
231 fin->view = NULL;
232 fin->iter = NULL;
233 fin->end = NULL;
234
235 if ( mapped_openView( fin ) != 0 )
236 {
237 CloseHandle( fin->map );
238 TidyFree( allocator, fin );
239 return -1;
240 }
241
242 fin->file = fp;
243 inp->sourceData = fin;
244
245 return 0;
246 }
247
freeMappedFileSource(TidyInputSource * inp,Bool closeIt)248 static void freeMappedFileSource( TidyInputSource* inp, Bool closeIt )
249 {
250 MappedFileSource* fin = (MappedFileSource*) inp->sourceData;
251 if ( closeIt && fin && fin->file != INVALID_HANDLE_VALUE )
252 {
253 if ( fin->view )
254 UnmapViewOfFile( fin->view );
255
256 CloseHandle( fin->map );
257 CloseHandle( fin->file );
258 }
259 TidyFree( fin->allocator, fin );
260 }
261
MappedFileInput(TidyDocImpl * doc,HANDLE fp,int encoding)262 StreamIn* MappedFileInput ( TidyDocImpl* doc, HANDLE fp, int encoding )
263 {
264 StreamIn *in = TY_(initStreamIn)( doc, encoding );
265 if ( initMappedFileSource( doc->allocator, &in->source, fp ) != 0 )
266 {
267 TY_(freeStreamIn)( in );
268 return NULL;
269 }
270 in->iotype = FileIO;
271 return in;
272 }
273
274
TY_(DocParseFileWithMappedFile)275 int TY_(DocParseFileWithMappedFile)( TidyDocImpl* doc, ctmbstr filnam ) {
276 int status = -ENOENT;
277 HANDLE fin = CreateFileA( filnam, GENERIC_READ, FILE_SHARE_READ, NULL,
278 OPEN_EXISTING, 0, NULL );
279
280 #if PRESERVE_FILE_TIMES
281 LONGLONG actime, modtime;
282 TidyClearMemory( &doc->filetimes, sizeof(doc->filetimes) );
283
284 if ( fin != INVALID_HANDLE_VALUE && cfgBool(doc,TidyKeepFileTimes) &&
285 GetFileTime(fin, NULL, (FILETIME*)&actime, (FILETIME*)&modtime) )
286 {
287 #define TY_I64(str) TYDYAPPEND(str,LL)
288 #if _MSC_VER < 1300 && !defined(__GNUC__) /* less than msvc++ 7.0 */
289 # undef TY_I64
290 # define TY_I64(str) TYDYAPPEND(str,i64)
291 #endif
292 doc->filetimes.actime =
293 (time_t)( ( actime - TY_I64(116444736000000000)) / 10000000 );
294
295 doc->filetimes.modtime =
296 (time_t)( ( modtime - TY_I64(116444736000000000)) / 10000000 );
297 }
298 #endif
299
300 if ( fin != INVALID_HANDLE_VALUE )
301 {
302 StreamIn* in = MappedFileInput( doc, fin,
303 cfg( doc, TidyInCharEncoding ) );
304 if ( !in )
305 {
306 CloseHandle( fin );
307 return -ENOMEM;
308 }
309
310 status = TY_(DocParseStream)( doc, in );
311 freeMappedFileSource( &in->source, yes );
312 TY_(freeStreamIn)( in );
313 }
314 else /* Error message! */
315 TY_(FileError)( doc, filnam, TidyError );
316 return status;
317 }
318
319 #endif
320
321
322 /*
323 * local variables:
324 * mode: c
325 * indent-tabs-mode: nil
326 * c-basic-offset: 4
327 * eval: (c-set-offset 'substatement-open 0)
328 * end:
329 */
330