288 lines
6.7 KiB
C++
288 lines
6.7 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
/*
|
|
* file.cpp
|
|
*
|
|
* an object representing a file and the lines of text it contains.
|
|
*
|
|
* a FILEDATA object is initialised with a DIRITEM handle from which it
|
|
* can get a filename. It knows how to supply a list of LINE handles for the
|
|
* lines of text in the file.
|
|
*
|
|
* The file is read into memory optionally on creation of the FILEDATA object:
|
|
* otherwise, at the first call to file_getlinelist. It can be discarded
|
|
* by calling file_discardlines: in this case, it will be re-read next time
|
|
* file_getlinelist is called.
|
|
*
|
|
* calling file_reset will cause line_reset to be called for all lines
|
|
* in the list. This clears any links and forces a recalc of line checksums.
|
|
*
|
|
* we allocate all memory using HeapAlloc
|
|
*
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include "sdkdiff.h"
|
|
#include "list.h"
|
|
#include "line.h"
|
|
#include "scandir.h"
|
|
#include "file.h"
|
|
#include "wdiffrc.h"
|
|
|
|
extern HANDLE hHeap;
|
|
|
|
/*
|
|
* we return FILEDATA handles: these are pointers to a
|
|
* filedata struct defined here.
|
|
*/
|
|
struct filedata {
|
|
|
|
DIRITEM diritem; /* handle to file name information */
|
|
LIST lines; /* NULL if lines not read in */
|
|
|
|
BOOL fUnicode;
|
|
};
|
|
|
|
|
|
void file_readlines(FILEDATA fd);
|
|
|
|
/*-- external functions ---------------------------------------------- */
|
|
|
|
/*
|
|
* create a new filedata, given the DIRITEM handle which will give us
|
|
* the file name. If bRead is TRUE, read the file into memory.
|
|
*/
|
|
FILEDATA
|
|
file_new(DIRITEM fiName, BOOL bRead)
|
|
{
|
|
FILEDATA fd;
|
|
|
|
fd = (FILEDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct filedata));
|
|
if (fd == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
fd->diritem = fiName;
|
|
fd->lines = NULL;
|
|
|
|
if (bRead) {
|
|
file_readlines(fd);
|
|
}
|
|
|
|
return(fd);
|
|
}
|
|
|
|
/*
|
|
* return a handle to the DIRITEM used to create this FILEDATA
|
|
*/
|
|
DIRITEM
|
|
file_getdiritem(FILEDATA fd)
|
|
{
|
|
if (fd == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
return(fd->diritem);
|
|
}
|
|
|
|
|
|
/*
|
|
* delete a filedata and its associated list of lines. note that the diritem
|
|
* is not deleted (this is owned by the DIRLIST, and will be deleted
|
|
* when the DIRLIST is deleted)
|
|
*/
|
|
void
|
|
file_delete(FILEDATA fd)
|
|
{
|
|
if (fd == NULL) {
|
|
return;
|
|
}
|
|
|
|
/* throw away the line list, if there is one */
|
|
file_discardlines(fd);
|
|
|
|
HeapFree(GetProcessHeap(), NULL, fd);
|
|
}
|
|
|
|
/*
|
|
* return a handle to a list of lines in this file. the items in the
|
|
* list are LINE handles.
|
|
*
|
|
* the first call to this function will cause the file to be read into
|
|
* memory if bRead was FALSE on the call to file_new, or if file_discardlines
|
|
* has since been called.
|
|
*
|
|
* the list of lines returned should not be deleted except by calls to
|
|
* file_delete or file_discardlines.
|
|
*/
|
|
LIST
|
|
file_getlinelist(FILEDATA fd)
|
|
{
|
|
if (fd == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (fd->lines == NULL) {
|
|
file_readlines(fd);
|
|
}
|
|
return(fd->lines);
|
|
}
|
|
|
|
|
|
/*
|
|
* discard the list of lines associated with a file. this will cause
|
|
* the file to be re-read next time file_getlinelist is called.
|
|
*/
|
|
void
|
|
file_discardlines(FILEDATA fd)
|
|
{
|
|
LINE line;
|
|
|
|
if (fd == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (fd->lines != NULL) {
|
|
|
|
/* clear each line to free any memory associated
|
|
* with them, then discard the entire list
|
|
*/
|
|
for( line=(LINE)List_First(fd->lines); line!=NULL; line = (LINE)List_Next((LPVOID)line)) {
|
|
line_delete(line);
|
|
}
|
|
List_Destroy(&fd->lines);
|
|
}
|
|
|
|
/* this is probably done in List_Destroy, but better do it anyway*/
|
|
fd->lines = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* force a reset of each line in the list. line_reset discards any
|
|
* links between lines, and any hashcode information. This would be used if
|
|
* the compare options or hashcode options have changed.
|
|
*/
|
|
void
|
|
file_reset(FILEDATA fd)
|
|
{
|
|
LINE line;
|
|
|
|
if (fd == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (fd->lines != NULL) {
|
|
for( line=(LINE)List_First(fd->lines); line!=NULL; line =(LINE) List_Next((LPVOID)line)) {
|
|
line_reset(line);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* return a checksum identical to one obtained through dir_getchecksum
|
|
* This will recalculate it for local files.
|
|
*/
|
|
DWORD
|
|
file_checksum(FILEDATA fd)
|
|
{
|
|
return(dir_getchecksum(fd->diritem));
|
|
}
|
|
|
|
|
|
/*
|
|
* Retrieve the checksum that we have for this file, valid or not.
|
|
* Indicate in bValid whether it is actually valid or not.
|
|
* Do NOT recalculate it or make any new attempt to read the file!
|
|
*/
|
|
DWORD file_retrievechecksum(FILEDATA fd, BOOL * bValid)
|
|
{
|
|
if (dir_validchecksum(fd->diritem)) {
|
|
*bValid = TRUE;
|
|
return dir_getchecksum(fd->diritem);
|
|
} else {
|
|
*bValid = FALSE;
|
|
return 0;
|
|
}
|
|
} /* file_retrievechecksum */
|
|
|
|
|
|
/* retrieve the filetime for the file */
|
|
FILETIME file_GetTime(FILEDATA fd)
|
|
{ return dir_GetFileTime(fd->diritem);
|
|
}
|
|
|
|
/* --- internal functions -------------------------------------------*/
|
|
|
|
/*
|
|
* read the file into a list of lines.
|
|
*
|
|
* we use the buffered read functions to read a block at a time, and
|
|
* return us a pointer to a line within the block. The line we are
|
|
* pointed to is not null terminated. from this we do a line_new: this
|
|
* will make a copy of the text (since we want to re-use the buffer), and
|
|
* will null-terminate its copy.
|
|
*
|
|
* we also give each line a number, starting at one.
|
|
*/
|
|
void
|
|
file_readlines(FILEDATA fd)
|
|
{
|
|
LPSTR textp;
|
|
LPWSTR pwzText;
|
|
int cwch;
|
|
HANDLE fh;
|
|
FILEBUFFER fbuf;
|
|
int linelen;
|
|
int linenr = 1;
|
|
HCURSOR hcurs;
|
|
|
|
hcurs = SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
|
|
/* open the file */
|
|
fh = dir_openfile(fd->diritem);
|
|
|
|
if (fh == INVALID_HANDLE_VALUE) {
|
|
TRACE_ERROR(LoadRcString(IDS_ERR_OPENING_FILE), FALSE);
|
|
SetCursor(hcurs);
|
|
return;
|
|
}
|
|
/* initialise the file buffering */
|
|
fbuf = readfile_new(fh, &fd->fUnicode);
|
|
|
|
if (fbuf)
|
|
{
|
|
/* make an empty list for the files */
|
|
fd->lines = List_Create();
|
|
|
|
while ( (textp = readfile_next(fbuf, &linelen, &pwzText, &cwch)) != NULL) {
|
|
if (linelen>0) { /* readfile failure gives linelen==-1 */
|
|
line_new(textp, linelen, pwzText, cwch, linenr++, fd->lines);
|
|
} else {
|
|
line_new("!! <unreadable> !!", 20, NULL, 0, linenr++,fd->lines);
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/* close filehandle and free buffer */
|
|
readfile_delete(fbuf);
|
|
}
|
|
|
|
dir_closefile(fd->diritem, fh);
|
|
|
|
SetCursor(hcurs);
|
|
}
|
|
|
|
BOOL
|
|
file_IsUnicode(FILEDATA fd)
|
|
{
|
|
return fd->fUnicode;
|
|
}
|