334 lines
8.1 KiB
C
334 lines
8.1 KiB
C
/* Interface to mmap style I/O
|
|
|
|
(c) 2006-2008 (W3C) MIT, ERCIM, Keio University
|
|
See tidy.h for the copyright notice.
|
|
|
|
Originally contributed by Cory Nelson and Nuno Lopes
|
|
|
|
*/
|
|
|
|
/* keep these here to keep file non-empty */
|
|
#include "forward.h"
|
|
#include "mappedio.h"
|
|
|
|
#if SUPPORT_POSIX_MAPPED_FILES
|
|
|
|
#include "fileio.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
typedef struct
|
|
{
|
|
TidyAllocator *allocator;
|
|
const byte *base;
|
|
size_t pos, size;
|
|
} MappedFileSource;
|
|
|
|
static int TIDY_CALL mapped_getByte( void* sourceData )
|
|
{
|
|
MappedFileSource* fin = (MappedFileSource*) sourceData;
|
|
return fin->base[fin->pos++];
|
|
}
|
|
|
|
static Bool TIDY_CALL mapped_eof( void* sourceData )
|
|
{
|
|
MappedFileSource* fin = (MappedFileSource*) sourceData;
|
|
return (fin->pos >= fin->size);
|
|
}
|
|
|
|
static void TIDY_CALL mapped_ungetByte( void* sourceData, byte ARG_UNUSED(bv) )
|
|
{
|
|
MappedFileSource* fin = (MappedFileSource*) sourceData;
|
|
fin->pos--;
|
|
}
|
|
|
|
int TY_(initFileSource)( TidyAllocator *allocator, TidyInputSource* inp, FILE* fp )
|
|
{
|
|
MappedFileSource* fin;
|
|
struct stat sbuf;
|
|
int fd;
|
|
|
|
fin = (MappedFileSource*) TidyAlloc( allocator, sizeof(MappedFileSource) );
|
|
if ( !fin )
|
|
return -1;
|
|
|
|
fd = fileno(fp);
|
|
if ( fstat(fd, &sbuf) == -1
|
|
|| sbuf.st_size == 0
|
|
|| (fin->base = mmap(0, fin->size = sbuf.st_size, PROT_READ,
|
|
MAP_SHARED, fd, 0)) == MAP_FAILED)
|
|
{
|
|
TidyFree( allocator, fin );
|
|
/* Fallback on standard I/O */
|
|
return TY_(initStdIOFileSource)( allocator, inp, fp );
|
|
}
|
|
|
|
fin->pos = 0;
|
|
fin->allocator = allocator;
|
|
fclose(fp);
|
|
|
|
inp->getByte = mapped_getByte;
|
|
inp->eof = mapped_eof;
|
|
inp->ungetByte = mapped_ungetByte;
|
|
inp->sourceData = fin;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void TY_(freeFileSource)( TidyInputSource* inp, Bool closeIt )
|
|
{
|
|
if ( inp->getByte == mapped_getByte )
|
|
{
|
|
MappedFileSource* fin = (MappedFileSource*) inp->sourceData;
|
|
munmap( (void*)fin->base, fin->size );
|
|
TidyFree( fin->allocator, fin );
|
|
}
|
|
else
|
|
TY_(freeStdIOFileSource)( inp, closeIt );
|
|
}
|
|
|
|
#endif /* SUPPORT_POSIX_MAPPED_FILES */
|
|
|
|
|
|
#if defined(_WIN32)
|
|
# if defined(_MSC_VER) && (_MSC_VER < 1300) /* less than msvc++ 7.0 */
|
|
# pragma warning(disable:4115) /* named type definition in parentheses in windows headers */
|
|
# endif
|
|
# include <windows.h>
|
|
# include <errno.h>
|
|
# include "streamio.h"
|
|
# include "tidy-int.h"
|
|
# include "message.h"
|
|
|
|
typedef struct _fp_input_mapped_source
|
|
{
|
|
TidyAllocator *allocator;
|
|
LONGLONG size, pos;
|
|
HANDLE file, map;
|
|
byte *view, *iter, *end;
|
|
unsigned int gran;
|
|
} MappedFileSource;
|
|
|
|
static int mapped_openView( MappedFileSource *data )
|
|
{
|
|
DWORD numb = ( ( data->size - data->pos ) > data->gran ) ?
|
|
data->gran : (DWORD)( data->size - data->pos );
|
|
|
|
if ( data->view )
|
|
{
|
|
UnmapViewOfFile( data->view );
|
|
data->view = NULL;
|
|
}
|
|
|
|
data->view = MapViewOfFile( data->map, FILE_MAP_READ,
|
|
(DWORD)( data->pos >> 32 ),
|
|
(DWORD)data->pos, numb );
|
|
|
|
if ( !data->view ) return -1;
|
|
|
|
data->iter = data->view;
|
|
data->end = data->iter + numb;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int TIDY_CALL mapped_getByte( void *sourceData )
|
|
{
|
|
MappedFileSource *data = sourceData;
|
|
|
|
if ( !data->view || data->iter >= data->end )
|
|
{
|
|
data->pos += data->gran;
|
|
|
|
if ( data->pos >= data->size || mapped_openView(data) != 0 )
|
|
return EndOfStream;
|
|
}
|
|
|
|
return *( data->iter++ );
|
|
}
|
|
|
|
static Bool TIDY_CALL mapped_eof( void *sourceData )
|
|
{
|
|
MappedFileSource *data = sourceData;
|
|
return ( data->pos >= data->size );
|
|
}
|
|
|
|
static void TIDY_CALL mapped_ungetByte( void *sourceData, byte ARG_UNUSED(bt) )
|
|
{
|
|
MappedFileSource *data = sourceData;
|
|
|
|
if ( data->iter >= data->view )
|
|
{
|
|
--data->iter;
|
|
return;
|
|
}
|
|
|
|
if ( data->pos < data->gran )
|
|
{
|
|
assert(0);
|
|
return;
|
|
}
|
|
|
|
data->pos -= data->gran;
|
|
mapped_openView( data );
|
|
}
|
|
|
|
static int initMappedFileSource( TidyAllocator *allocator, TidyInputSource* inp, HANDLE fp )
|
|
{
|
|
MappedFileSource* fin = NULL;
|
|
|
|
inp->getByte = mapped_getByte;
|
|
inp->eof = mapped_eof;
|
|
inp->ungetByte = mapped_ungetByte;
|
|
|
|
fin = (MappedFileSource*) TidyAlloc( allocator, sizeof(MappedFileSource) );
|
|
if ( !fin )
|
|
return -1;
|
|
|
|
# if defined(__MINGW32__)
|
|
{
|
|
DWORD lowVal, highVal;
|
|
lowVal = GetFileSize(fp, &highVal);
|
|
if ((lowVal == INVALID_FILE_SIZE) && (GetLastError() != NO_ERROR))
|
|
{
|
|
TidyFree(allocator, fin);
|
|
return -1;
|
|
}
|
|
fin->size = highVal;
|
|
fin->size = (fin->size << 32);
|
|
fin->size += lowVal;
|
|
}
|
|
# else /* NOT a MinGW build */
|
|
# if defined(_MSC_VER) && (_MSC_VER < 1300) /* less than msvc++ 7.0 */
|
|
{
|
|
LARGE_INTEGER* pli = (LARGE_INTEGER *)&fin->size;
|
|
(DWORD)pli->LowPart = GetFileSize( fp, (DWORD *)&pli->HighPart );
|
|
if ( GetLastError() != NO_ERROR || fin->size <= 0 )
|
|
{
|
|
TidyFree(allocator, fin);
|
|
return -1;
|
|
}
|
|
}
|
|
# else
|
|
if ( !GetFileSizeEx( fp, (LARGE_INTEGER*)&fin->size )
|
|
|| fin->size <= 0 )
|
|
{
|
|
TidyFree(allocator, fin);
|
|
return -1;
|
|
}
|
|
# endif
|
|
# endif /* MinGW y/n */
|
|
|
|
fin->map = CreateFileMapping( fp, NULL, PAGE_READONLY, 0, 0, NULL );
|
|
|
|
if ( !fin->map )
|
|
{
|
|
TidyFree(allocator, fin);
|
|
return -1;
|
|
}
|
|
|
|
{
|
|
SYSTEM_INFO info;
|
|
GetSystemInfo( &info );
|
|
fin->gran = info.dwAllocationGranularity;
|
|
}
|
|
|
|
fin->allocator = allocator;
|
|
fin->pos = 0;
|
|
fin->view = NULL;
|
|
fin->iter = NULL;
|
|
fin->end = NULL;
|
|
|
|
if ( mapped_openView( fin ) != 0 )
|
|
{
|
|
CloseHandle( fin->map );
|
|
TidyFree( allocator, fin );
|
|
return -1;
|
|
}
|
|
|
|
fin->file = fp;
|
|
inp->sourceData = fin;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void freeMappedFileSource( TidyInputSource* inp, Bool closeIt )
|
|
{
|
|
MappedFileSource* fin = (MappedFileSource*) inp->sourceData;
|
|
if ( closeIt && fin && fin->file != INVALID_HANDLE_VALUE )
|
|
{
|
|
if ( fin->view )
|
|
UnmapViewOfFile( fin->view );
|
|
|
|
CloseHandle( fin->map );
|
|
CloseHandle( fin->file );
|
|
}
|
|
TidyFree( fin->allocator, fin );
|
|
}
|
|
|
|
StreamIn* MappedFileInput ( TidyDocImpl* doc, HANDLE fp, int encoding )
|
|
{
|
|
StreamIn *in = TY_(initStreamIn)( doc, encoding );
|
|
if ( initMappedFileSource( doc->allocator, &in->source, fp ) != 0 )
|
|
{
|
|
TY_(freeStreamIn)( in );
|
|
return NULL;
|
|
}
|
|
in->iotype = FileIO;
|
|
return in;
|
|
}
|
|
|
|
|
|
int TY_(DocParseFileWithMappedFile)( TidyDocImpl* doc, ctmbstr filnam ) {
|
|
int status = -ENOENT;
|
|
HANDLE fin = CreateFileA( filnam, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, 0, NULL );
|
|
|
|
# if PRESERVE_FILE_TIMES
|
|
LONGLONG actime, modtime;
|
|
TidyClearMemory( &doc->filetimes, sizeof(doc->filetimes) );
|
|
|
|
if ( fin != INVALID_HANDLE_VALUE && cfgBool(doc,TidyKeepFileTimes) &&
|
|
GetFileTime(fin, NULL, (FILETIME*)&actime, (FILETIME*)&modtime) )
|
|
{
|
|
# define TY_I64(str) TYDYAPPEND(str,LL)
|
|
# if _MSC_VER < 1300 && !defined(__GNUC__) /* less than msvc++ 7.0 */
|
|
# undef TY_I64
|
|
# define TY_I64(str) TYDYAPPEND(str,i64)
|
|
# endif
|
|
doc->filetimes.actime =
|
|
(time_t)( ( actime - TY_I64(116444736000000000)) / 10000000 );
|
|
|
|
doc->filetimes.modtime =
|
|
(time_t)( ( modtime - TY_I64(116444736000000000)) / 10000000 );
|
|
}
|
|
# endif /* PRESERVE_FILE_TIMES */
|
|
|
|
if ( fin != INVALID_HANDLE_VALUE )
|
|
{
|
|
StreamIn* in = MappedFileInput( doc, fin,
|
|
cfg( doc, TidyInCharEncoding ) );
|
|
if ( !in )
|
|
{
|
|
CloseHandle( fin );
|
|
return -ENOMEM;
|
|
}
|
|
|
|
status = TY_(DocParseStream)( doc, in );
|
|
freeMappedFileSource( &in->source, yes );
|
|
TY_(freeStreamIn)( in );
|
|
}
|
|
else /* Error message! */
|
|
TY_(ReportFileError)( doc, filnam, FILE_CANT_OPEN );
|
|
return status;
|
|
}
|
|
|
|
#endif /* defined(_WIN32) */
|
|
|