{
IntfWin – модуль, реализующий интерфейс между модулями Utils, FileIO и
программной платформой WIN32.
Copyright © 2017 Малик Разработчик
Это свободная программа: вы можете перераспространять её и/или
изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она может быть полезна,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
}
unit IntfWin;
{$MODE DELPHI,EXTENDEDSYNTAX ON}
interface
uses
Windows, Lang;
{$ASMMODE INTEL,CALLING REGISTER,INLINE ON,GOTO ON}
{$H+,I-,J-,M-,Q-,R-,T-}
type
OSIntfFileOpenID = HANDLE;
OSIntfFileFindID = class(_Object)
public
constructor create(); overload;
constructor create(findID: HANDLE; const findData: WIN32_FIND_DATAW); overload;
procedure close(); virtual; abstract;
function findNext(): boolean; virtual; abstract;
private
findID: HANDLE;
findData: WIN32_FIND_DATAW;
end;
{$I FIOINTF.INC}
implementation
type
OSIntfDriveFindWin32 = class(OSIntfFileFindID)
public
constructor create();
procedure close(); override;
function findNext(): boolean; override;
end;
OSIntfFileFindWin32 = class(OSIntfFileFindID)
public
constructor create(findID: HANDLE; const findData: WIN32_FIND_DATAW);
procedure close(); override;
function findNext(): boolean; override;
end;
{ unit private members }
function buildOSIntfTime(year, month, day,
hour, minute, second, millis: int): OSIntfDateTimeRecord;
begin
result.year := year;
result.month := month;
result.day := day;
result.reserved := 0;
result.hour := hour;
result.minute := minute;
result.second := second;
result.millis := millis;
end;
function systemTimeToOSIntf(const st: SYSTEMTIME): OSIntfDateTimeRecord;
begin
result.year := st.year;
result.month := st.month;
result.day := st.day;
result.reserved := 0;
result.hour := st.hour;
result.minute := st.minute;
result.second := st.second;
result.millis := st.millisecond;
end;
function fileTimeToOSIntf(const ft: FILETIME): OSIntfDateTimeRecord;
var
st: SYSTEMTIME;
begin
if (ft.dwLowDateTime = 0) and (ft.dwHighDateTime = 0) then begin
result := buildOSIntfTime(0, 0, 0, 0, 0, 0, 0);
exit;
end;
initialize(st);
fileTimeToSystemTime(ft, st);
result := systemTimeToOSIntf(st);
end;
function osintfTimeToFile(const ot: OSIntfDateTimeRecord): FILETIME;
var
st: SYSTEMTIME;
begin
initialize(result);
st.year := Word(ot.year);
st.month := Word(ot.month);
st.dayOfWeek := Word(-1);
st.day := Word(ot.day);
st.hour := Word(ot.hour);
st.minute := Word(ot.minute);
st.second := Word(ot.second);
st.millisecond := Word(ot.millis);
systemTimeToFileTime(st, result);
end;
{ OSIntfFileFindID }
constructor OSIntfFileFindID.create();
begin
inherited create();
end;
constructor OSIntfFileFindID.create(findID: HANDLE; const findData: WIN32_FIND_DATAW);
begin
inherited create();
self.findID := findID;
self.findData := findData;
end;
{ OSIntfDriveFindWin32 }
constructor OSIntfDriveFindWin32.create();
begin
inherited create();
with findData do begin
dwFileAttributes := OSINTF_FILE_ATTR_DIRECTORY;
ftCreationTime.dwLowDateTime := 0;
ftCreationTime.dwHighDateTime := 0;
ftLastWriteTime.dwLowDateTime := 0;
ftLastWriteTime.dwHighDateTime := 0;
ftLastAccessTime.dwLowDateTime := 0;
ftLastAccessTime.dwHighDateTime := 0;
nFileSizeLow := 0;
nFileSizeHigh := 0;
dwReserved0 := 0;
dwReserved1 := 0;
cFileName[0] := uchar(int('A') - 1);
cFileName[1] := ':';
cFileName[2] := #$0000;
cAlternateFileName[0] := #$0000;
end;
findNext();
end;
procedure OSIntfDriveFindWin32.close();
begin
end;
function OSIntfDriveFindWin32.findNext(): boolean;
var
driveName: PWideChar;
driveType: DWORD;
begin
driveName := @(findData.cFileName);
repeat
inc(driveName[0]);
if driveName[0] > 'Z' then begin
result := false;
exit;
end;
driveType := getDriveTypeW(PWideChar(UnicodeString(driveName) + DIRECTORY_SEPARATOR));
if (driveType <> DRIVE_UNKNOWN) and (driveType <> DRIVE_NO_ROOT_DIR) then begin
result := true;
exit;
end;
until false;
end;
{ OSIntfFileFindWin32 }
constructor OSIntfFileFindWin32.create(findID: HANDLE; const findData: WIN32_FIND_DATAW);
begin
inherited create(findID, findData);
end;
procedure OSIntfFileFindWin32.close();
begin
findClose(findID);
end;
function OSIntfFileFindWin32.findNext(): boolean;
begin
result := findNextFileW(findID, @findData);
end;
{ functions }
{ date & time }
function osintfGetCurrentUTCOffsetInMillis(): int;
var
tzInfo: TIME_ZONE_INFORMATION;
begin
tzInfo.bias := int(0);
getTimeZoneInformation(@tzInfo);
result := -60000 * tzInfo.bias;
end;
function osintfGetCurrentUTCTime(): OSIntfDateTimeRecord;
var
st: SYSTEMTIME;
begin
initialize(st);
getSystemTime(@st);
result := systemTimeToOSIntf(st);
end;
{ file system }
function osintfFileNameMaximumLength(): int;
begin
result := MAX_PATH;
end;
function osintfFileNameCaseSensitive(): boolean;
begin
result := false;
end;
function osintfFileNameValid(const osFileName: UnicodeString): boolean;
var
i: int;
len: int;
c: uchar;
begin
len := length(osFileName);
if len = 0 then begin
result := true;
exit;
end;
if (len < 2) or (len > MAX_PATH) then begin
result := false;
exit;
end;
c := osFileName[1];
if ((c < 'A') or (c > 'Z')) and ((c < 'a') or (c > 'z')) or (osFileName[2] <> ':') or
(len >= 3) and (osFileName[3] <> DIRECTORY_SEPARATOR) then begin
result := false;
exit;
end;
for i := 4 to len do begin
case osFileName[i] of
#$0000, '/', ':', '*', '?', '"', '<', '>', '|': begin
result := false;
exit;
end;
'\': begin
if osFileName[i - 1] = '\' then begin
result := false;
exit;
end;
end;
end;
end;
result := true;
end;
function osintfFileNameToVFS(const osFileName: UnicodeString): UnicodeString;
label
label0;
var
i: int;
j: int;
cc: int;
len: int;
c: uchar;
begin
result := stringCopy(osFileName);
len := length(result);
i := 2;
while i <= len do begin
c := result[i];
case c of
'$': begin
if i < len - 1 then begin
cc := 0;
for j := 1 to 2 do begin
c := result[i + j];
case c of
'0'..'9': begin
cc := (cc shl 4) + (int(c) - int('0'));
end;
'A'..'F': begin
cc := (cc shl 4) + (int(c) - (int('A') - $0a));
end;
'a'..'f': begin
cc := (cc shl 4) + (int(c) - (int('a') - $0a));
end;
else
goto label0;
end;
end;
result[i] := uchar(cc);
delete(result, i + 1, 2);
dec(len, 2);
end;
end;
'\': begin
result[i] := '/';
end;
end;
label0:
inc(i);
end;
end;
function osintfFileNameToOS(const vfsFileName: UnicodeString): UnicodeString;
var
i: int;
len: int;
c: uchar;
begin
result := stringCopy(vfsFileName);
len := length(result);
if (len > 0) and (result[1] = '/') then begin
delete(result, 1, 1);
dec(len);
end;
i := 1;
while i <= len do begin
c := result[i];
case c of
#$0000..#$001f, '$', '\', ':', '*', '?', '"', '<', '>', '|': begin
if (i <> 2) or (c <> ':') then begin
result[i] := '$';
insert(stringToUTF16(DIGITS[((int(c) shr 4) and $0f) + 1] +
DIGITS[(int(c) and $0f) + 1]), result, i + 1);
inc(i, 2);
end;
end;
'/': begin
result[i] := '\';
end;
end;
inc(i);
end;
end;
function osintfFileWriteAttributes(const osFileName: UnicodeString; const attributes: int;
const creationTime, lastWriteTime, lastAccessTime: OSIntfDateTimeRecord): boolean;
var
fileID: HANDLE;
realAttr: DWORD;
crTime: FILETIME;
lwTime: FILETIME;
laTime: FILETIME;
begin
realAttr := getFileAttributesW(PWideChar(osFileName));
if int(realAttr) = -1 then begin
result := false;
exit;
end;
realAttr := (realAttr and not DWORD(OSINTF_FILE_ATTR_MASK)) or
DWORD(attributes and OSINTF_FILE_ATTR_MASK);
crTime := osintfTimeToFile(creationTime);
lwTime := osintfTimeToFile(lastWriteTime);
laTime := osintfTimeToFile(lastAccessTime);
if not setFileAttributesW(PWideChar(osFileName), realAttr) then begin
result := false;
exit;
end;
fileID := createFileW(PWideChar(osFileName), GENERIC_WRITE, FILE_SHARE_WRITE, nil,
OPEN_EXISTING, realAttr or FILE_FLAG_BACKUP_SEMANTICS, 0);
if fileID = INVALID_HANDLE_VALUE then begin
result := false;
exit;
end;
try
if not setFileTime(fileID, @crTime, @laTime, @lwTime) then begin
result := false;
exit;
end;
finally
closeHandle(fileID);
end;
result := true;
end;
function osintfFileReadAttributes(const osFileName: UnicodeString; out attributes: int;
out creationTime, lastWriteTime, lastAccessTime: OSIntfDateTimeRecord): boolean;
var
fileID: HANDLE;
realAttr: DWORD;
crTime: FILETIME;
lwTime: FILETIME;
laTime: FILETIME;
begin
realAttr := getFileAttributesW(PWideChar(osFileName));
if int(realAttr) = -1 then begin
result := false;
exit;
end;
fileID := createFileW(PWideChar(osFileName), GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, realAttr or FILE_FLAG_BACKUP_SEMANTICS, 0);
if fileID = INVALID_HANDLE_VALUE then begin
result := false;
exit;
end;
try
if not getFileTime(fileID, @crTime, @laTime, @lwTime) then begin
result := false;
exit;
end;
finally
closeHandle(fileID);
end;
attributes := int(realAttr) and OSINTF_FILE_ATTR_MASK;
creationTime := fileTimeToOSIntf(crTime);
lastWriteTime := fileTimeToOSIntf(lwTime);
lastAccessTime := fileTimeToOSIntf(laTime);
result := true;
end;
function osintfFileFindFirst(const osBasePath: UnicodeString;
out findInfo: OSIntfFileFindInfo): boolean;
var
c: uchar;
len: int;
driveType: DWORD;
findID: HANDLE;
findData: WIN32_FIND_DATAW;
findObject: OSIntfFileFindID;
defaultTime: OSIntfDateTimeRecord;
begin
len := length(osBasePath);
if len = 0 then begin
findObject := OSIntfDriveFindWin32.create();
defaultTime := buildOSIntfTime(0, 0, 0, 0, 0, 0, 0);
findInfo.attributes := OSINTF_FILE_ATTR_DIRECTORY;
findInfo.creationTime := defaultTime;
findInfo.lastWriteTime := defaultTime;
findInfo.lastAccessTime := defaultTime;
findInfo.size := 0;
findInfo.name := findObject.findData.cFileName;
findInfo.findID := findObject;
result := true;
exit;
end;
if len = 2 then begin
c := osBasePath[1];
if ((c >= 'A') and (c <= 'Z') or (c >= 'a') and (c <= 'z')) and
(osBasePath[2] = ':') then begin
driveType := getDriveTypeW(PWideChar(osBasePath + DIRECTORY_SEPARATOR));
if (driveType <> DRIVE_UNKNOWN) and (driveType <> DRIVE_NO_ROOT_DIR) then begin
defaultTime := buildOSIntfTime(0, 0, 0, 0, 0, 0, 0);
findInfo.attributes := OSINTF_FILE_ATTR_DIRECTORY;
findInfo.creationTime := defaultTime;
findInfo.lastWriteTime := defaultTime;
findInfo.lastAccessTime := defaultTime;
findInfo.size := 0;
findInfo.name := stringToUpperCase(c) + ':';
findInfo.findID := nil;
result := true;
exit;
end;
end;
end;
if osintfFileNameValid(osBasePath) then begin
initialize(findData);
if osBasePath[len] <> DIRECTORY_SEPARATOR then begin
findID := findFirstFileW(PWideChar(osBasePath), @findData);
if findID <> INVALID_HANDLE_VALUE then begin
closeHandle(findID);
findInfo.attributes := int(findData.dwFileAttributes) and OSINTF_FILE_ATTR_MASK;
findInfo.creationTime := fileTimeToOSIntf(findData.ftCreationTime);
findInfo.lastWriteTime := fileTimeToOSIntf(findData.ftLastWriteTime);
findInfo.lastAccessTime := fileTimeToOSIntf(findData.ftLastAccessTime);
findInfo.size := longBuild(int(findData.nFileSizeHigh),
int(findData.nFileSizeLow));
findInfo.name := findData.cFileName;
findInfo.findID := nil;
result := true;
exit;
end;
end else begin
findID := findFirstFileW(PWideChar(osBasePath + '*.*'), @findData);
if findID <> INVALID_HANDLE_VALUE then begin
findInfo.attributes := int(findData.dwFileAttributes) and OSINTF_FILE_ATTR_MASK;
findInfo.creationTime := fileTimeToOSIntf(findData.ftCreationTime);
findInfo.lastWriteTime := fileTimeToOSIntf(findData.ftLastWriteTime);
findInfo.lastAccessTime := fileTimeToOSIntf(findData.ftLastAccessTime);
findInfo.size := longBuild(int(findData.nFileSizeHigh),
int(findData.nFileSizeLow));
findInfo.name := findData.cFileName;
findInfo.findID := OSIntfFileFindWin32.create(findID, findData);
result := true;
exit;
end;
end;
end;
defaultTime := buildOSIntfTime(0, 0, 0, 0, 0, 0, 0);
findInfo.attributes := 0;
findInfo.creationTime := defaultTime;
findInfo.lastWriteTime := defaultTime;
findInfo.lastAccessTime := defaultTime;
findInfo.size := 0;
findInfo.name := '';
findInfo.findID := nil;
result := false;
end;
function osintfFileFindNext(var findInfo: OSIntfFileFindInfo): boolean;
var
findID: OSIntfFileFindID;
begin
findID := findInfo.findID;
if (findID <> nil) and findID.findNext() then begin
with findID.findData do begin
findInfo.attributes := int(dwFileAttributes) and OSINTF_FILE_ATTR_MASK;
findInfo.creationTime := fileTimeToOSIntf(ftCreationTime);
findInfo.lastWriteTime := fileTimeToOSIntf(ftLastWriteTime);
findInfo.lastAccessTime := fileTimeToOSIntf(ftLastAccessTime);
findInfo.size := longBuild(int(nFileSizeHigh), int(nFileSizeLow));
findInfo.name := cFileName;
end;
result := true;
exit;
end;
result := false;
end;
function osintfFileFindClose(var findInfo: OSIntfFileFindInfo): boolean;
var
findID: OSIntfFileFindID;
begin
findID := findInfo.findID;
if findID <> nil then begin
findID.close();
findID.free();
findInfo.findID := nil;
result := true;
exit;
end;
result := false;
end;
function osintfFileMove(const osFileSrcName, osFileDstName: UnicodeString): boolean;
begin
result := moveFileW(PWideChar(osFileSrcName), PWideChar(osFileDstName));
end;
function osintfFileDelete(const osFileName: UnicodeString): boolean;
begin
result := deleteFileW(PWideChar(osFileName));
end;
function osintfDirectoryCreate(const osDirName: UnicodeString): boolean;
begin
result := createDirectoryW(PWideChar(osDirName), nil);
end;
function osintfDirectoryDelete(const osDirName: UnicodeString): boolean;
begin
result := removeDirectoryW(PWideChar(osDirName));
end;
{ file operation }
function osintfFileCreate(const osFileName: UnicodeString;
out fileID: OSIntfFileOpenID): boolean;
begin
fileID := createFileW(PWideChar(osFileName), GENERIC_WRITE, 0, nil,
CREATE_ALWAYS, 0, 0);
result := fileID <> INVALID_HANDLE_VALUE;
end;
function osintfFileOpenForReadOnly(const osFileName: UnicodeString;
out fileID: OSIntfFileOpenID): boolean;
begin
fileID := createFileW(PWideChar(osFileName), GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, getFileAttributesW(PWideChar(osFileName)), 0);
result := fileID <> INVALID_HANDLE_VALUE;
end;
function osintfFileOpenForReadWrite(const osFileName: UnicodeString;
out fileID: OSIntfFileOpenID): boolean;
begin
fileID := createFileW(PWideChar(osFileName), GENERIC_READ + GENERIC_WRITE, 0, nil,
OPEN_EXISTING, getFileAttributesW(PWideChar(osFileName)), 0);
result := fileID <> INVALID_HANDLE_VALUE;
end;
function osintfFileOpenForAppending(const osFileName: UnicodeString;
out fileID: OSIntfFileOpenID): boolean;
var
pos: long;
begin
fileID := createFileW(PWideChar(osFileName), GENERIC_WRITE, 0, nil,
OPEN_EXISTING, getFileAttributesW(PWideChar(osFileName)), 0);
result := fileID <> INVALID_HANDLE_VALUE;
if result then begin
pos := 0;
setFilePointer(fileID, pos.ints[0], @(pos.ints[1]), FILE_END);
end;
end;
function osintfFileClose(var fileID: OSIntfFileOpenID): boolean;
begin
result := closeHandle(fileID);
if result then begin
fileID := 0;
end;
end;
function osintfFileSetSize(const fileID: OSIntfFileOpenID): boolean;
begin
result := setEndOfFile(fileID);
end;
function osintfFileGetSize(const fileID: OSIntfFileOpenID): long;
begin
result := 0;
result.ints[0] := int(getFileSize(fileID, @(result.ints[1])));
end;
function osintfFileSetPos(const fileID: OSIntfFileOpenID; pos: long): long;
begin
result := pos;
result.ints[0] := int(setFilePointer(fileID, pos.ints[0], @(result.ints[1]), FILE_BEGIN));
end;
function osintfFileSeek(const fileID: OSIntfFileOpenID; delta: long): long;
begin
result := 0;
result.ints[1] := delta.ints[1];
result.ints[0] := int(setFilePointer(fileID, delta.ints[0], @(result.ints[1]), FILE_CURRENT));
end;
function osintfFileRead(const fileID: OSIntfFileOpenID; dst: byte_ArraySimple; length: int): int;
var
readed: DWORD;
begin
readed := 0;
if readFile(fileID, dst^, length, readed, nil) then begin
result := int(readed);
exit;
end;
result := 0;
end;
function osintfFileWrite(const fileID: OSIntfFileOpenID; src: byte_ArraySimple; length: int): int;
var
writed: DWORD;
begin
writed := 0;
if writeFile(fileID, src^, length, writed, nil) then begin
result := int(writed);
exit;
end;
result := 0;
end;
end.