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