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