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