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