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