| 1 |
/////////////////////////////////////////////////////////// |
|---|
| 2 |
// GGBuildTools // |
|---|
| 3 |
// Набор утилит для сборки проектов Gipat Group // |
|---|
| 4 |
// Copyright (C) 2007 Gipat Group // |
|---|
| 5 |
// Распространяется на условиях // |
|---|
| 6 |
// Gipat Group's opened EI-editor-utility license // |
|---|
| 7 |
// версии 1.0 // |
|---|
| 8 |
// // |
|---|
| 9 |
// www.gipatgroup.org // |
|---|
| 10 |
/////////////////////////////////////////////////////////// |
|---|
| 11 |
|
|---|
| 12 |
//К работе над данным файлом приложили руки, ноги.... короче аффтары: |
|---|
| 13 |
// 1) Sagrer (sagrer@yandex.ru) |
|---|
| 14 |
|
|---|
| 15 |
//////////////////////////////////////////////////////////////////////// |
|---|
| 16 |
|
|---|
| 17 |
//////////////////////////////////////////////////// |
|---|
| 18 |
// Модуль для работы с файлами Flist // |
|---|
| 19 |
// В этом файле хранится файловый список. // |
|---|
| 20 |
// с дополнительной инфой вроде размера или // |
|---|
| 21 |
// чексуммы... // |
|---|
| 22 |
// // |
|---|
| 23 |
// версия формата - 2 // |
|---|
| 24 |
//////////////////////////////////////////////////// |
|---|
| 25 |
|
|---|
| 26 |
unit FlistFormat; |
|---|
| 27 |
|
|---|
| 28 |
{$mode objfpc}{$H+} |
|---|
| 29 |
|
|---|
| 30 |
interface |
|---|
| 31 |
|
|---|
| 32 |
uses |
|---|
| 33 |
Classes, SysUtils, Windows, LCLAnIniFile, crc, ExtraFileUtilsLcl, ExtraFunctionsLcl, |
|---|
| 34 |
TranslManager; |
|---|
| 35 |
|
|---|
| 36 |
const |
|---|
| 37 |
Flist_FormatVersion = 2; //Номер версии формата в данном сырце. |
|---|
| 38 |
//Дефолтные значения переменных класса.... |
|---|
| 39 |
Flist_Def_PathsAreAbsolute = false; //По умолчанию использовать относительные пути. |
|---|
| 40 |
Flist_Def_AddSize = true; //По умолчанию оставлять инфу о размере файла. |
|---|
| 41 |
Flist_Def_AddCRC32 = true; //По умолчанию высчитывать и писать файлам CRC32. |
|---|
| 42 |
Flist_Def_DoConsoleOutput = false; //По умолчанию инфу в консоль не выводить. |
|---|
| 43 |
Flist_Def_UseGroups = false; //По умолчанию группы не используем. |
|---|
| 44 |
Flist_Def_UsedGroups = ''; //По умолчанию список групп пуст. |
|---|
| 45 |
//Тип файла |
|---|
| 46 |
Flist_Filetype_File = 0; //Тип файла - файл. |
|---|
| 47 |
Flist_Filetype_Directory = 1; //Тип файла - директория. |
|---|
| 48 |
Flist_Filetype_Unknown = 2; //Тип файла - хз что. |
|---|
| 49 |
//Ответы CheckFile |
|---|
| 50 |
Flist_CheckFile_Identical = 0; //Файл идентичен. |
|---|
| 51 |
Flist_CheckFile_MismatchedCRC32 = 1; //Не совпадает CRC32. |
|---|
| 52 |
Flist_CheckFile_MismatchedSize = 2; //Не совпадает размер. |
|---|
| 53 |
Flist_CheckFile_ElementNotExists = 3; //Нет записи о файле в базе. |
|---|
| 54 |
Flist_CheckFile_FileNotExists = 4; //Файл на диске не существует. |
|---|
| 55 |
Flist_CheckFile_NothingExists = 5; //Не существует ни файла на диске ни записи о нем в массиве. |
|---|
| 56 |
Flist_CheckFile_Error = 6; //Ошибка. (какая - хз). |
|---|
| 57 |
Flist_CheckFile_NonIdentical = 7; //Не совпадает (чем - либо хз либо неважно). |
|---|
| 58 |
|
|---|
| 59 |
type |
|---|
| 60 |
|
|---|
| 61 |
RFlistFile = record //Структура для инфы о файле в списке. |
|---|
| 62 |
FilePath : AnsiString; //Путь к файлу. |
|---|
| 63 |
FileType : byte; //Тип файла - Flist_Filetype_* . |
|---|
| 64 |
FileSize : Int64; //Размер файла. |
|---|
| 65 |
CRC32 : Cardinal; //CRC32 файла. |
|---|
| 66 |
Group : AnsiString; //Группа файла. |
|---|
| 67 |
end; |
|---|
| 68 |
|
|---|
| 69 |
RComparedElement = record //Структура для инфы о проверенном элементе. |
|---|
| 70 |
FilePath : AnsiString; //Путь к файлу. |
|---|
| 71 |
FileType : byte; //Тип файла - Flist_Filetype_* . |
|---|
| 72 |
CheckResult : byte; //Результат сравнения списка и реального файла\папки. |
|---|
| 73 |
end; |
|---|
| 74 |
|
|---|
| 75 |
AComparedList = array of RComparedElement; //Тип массива с инфой о сравнении. |
|---|
| 76 |
|
|---|
| 77 |
TFlistFormat = class //Класс для работы с файлами формата Flist (*.flist). |
|---|
| 78 |
private |
|---|
| 79 |
//Закрытые переменные |
|---|
| 80 |
//[Main] |
|---|
| 81 |
ReallyUseGroups : Boolean; //Используются ли группы файлов. |
|---|
| 82 |
//Закрытые методы. |
|---|
| 83 |
function ParseFileType(const InputStr : AnsiString) : byte; //Вернуть код типа файла по строковому значению типа. |
|---|
| 84 |
function ReturnFileTypeStr(const InputCode : byte) : AnsiString; //Наоборот сгенерить значение типа файла из кода. |
|---|
| 85 |
public |
|---|
| 86 |
//Переменные и методы чтения\записи |
|---|
| 87 |
//[Main] |
|---|
| 88 |
PathsAreAbsolute : Boolean; //Используются ли абсолютные пути. Если false - то используются пути относительно места где лежит данный *.flist |
|---|
| 89 |
AddSize : Boolean; //Добавлять ли инфу о размере файла. |
|---|
| 90 |
AddCRC32 : Boolean; //Добавлять ли crc32 файла. |
|---|
| 91 |
FilesNum : LongInt; //Количество файлов в списке. |
|---|
| 92 |
function UseGroups : Boolean; //Используются ли группы файлов - возвращает значение, записать прямо его нельзя. |
|---|
| 93 |
UsedGroups : TStringList; //Список используемых групп файлов, актуальность должна обеспечиваться реализацией, работающей с форматом, рекомендуется применять для оптимизации. |
|---|
| 94 |
//[Files] |
|---|
| 95 |
FileList : array of RFlistFile; //Собсно массив с файлами (инфой про них). |
|---|
| 96 |
//Служебные |
|---|
| 97 |
ErrorMessage : AnsiString; //Сообщение о ошибке если была |
|---|
| 98 |
FileLoaded : boolean; //Если true - значит уже загружался какой-то файл. |
|---|
| 99 |
LoadedFileName : AnsiString; //Имя загруженного в последний раз файла. |
|---|
| 100 |
GlobalRoot : AnsiString; //Если тут пусто - глобальный корень та папка где лежит flist. |
|---|
| 101 |
DoConsoleOutput : boolean; //Если поставить true то по-возможности будет скидывать инфу о прогрессе в консоль. |
|---|
| 102 |
|
|---|
| 103 |
//Конструкторы-деструкторы... |
|---|
| 104 |
constructor Create; |
|---|
| 105 |
destructor Destroy; override; |
|---|
| 106 |
|
|---|
| 107 |
//Открытые методы... |
|---|
| 108 |
procedure Clear(); //Очистить инфу класса. |
|---|
| 109 |
function GetGlobalRoot() : AnsiString; //Вернуть корень. |
|---|
| 110 |
function Load(const FileName : AnsiString) : boolean; //Загрузить файл в класс. |
|---|
| 111 |
function Save(const FileName : AnsiString) : boolean; //Сохранить инфу из класса в файл. |
|---|
| 112 |
function ElementNameExists(const ElementName : AnsiString) : boolean; //Существует ли элемент с таким именем. |
|---|
| 113 |
function GetElementNumber(const ElementName : AnsiString) : Integer; //Какой номер у элемента с таким именем. |
|---|
| 114 |
function FileExistsHere(const FileName : AnsiString) : boolean; //Существует ли файл с таким именем. |
|---|
| 115 |
function GetFileNumberHere(const FileName : AnsiString) : Integer; //Какой номер у файла с таким именем. |
|---|
| 116 |
function DirExistsHere(const DirName : AnsiString) : boolean; //Существует ли дира с таким именем. |
|---|
| 117 |
function GetDirNumberHere(const DirName : AnsiString) : Integer; //Определить номер диры с таким именем. |
|---|
| 118 |
function GetRealElementName(const ElemName : AnsiString) : AnsiString; //Определить абсолютное имя для элемента |
|---|
| 119 |
function GetRealElementName(const ElemNum : Integer) : AnsiString; //Определить абсолютное имя для элемента с таким-то номером в списке. |
|---|
| 120 |
function AddFile(const FileName : AnsiString) : boolean; //Добавить файл. |
|---|
| 121 |
function AddRealFile(const FileName : AnsiString) : boolean; //Добавить реально существующий на диске файл (с подсчетом реальной инфы). |
|---|
| 122 |
function AddDirectory(const DirName : AnsiString) : boolean; //Добавить пустую диру. |
|---|
| 123 |
function AddRealDirectory(const DirName : AnsiString; const Recursive : boolean) : boolean; //Добавить реальную диру с подсчетом всей инфы по файлам. |
|---|
| 124 |
function RemoveFile(const FileName : AnsiString) : boolean; //Удалить файл из базы. |
|---|
| 125 |
function RemoveDirectory(const DirName : AnsiString) : boolean; //Удалить диру (со всеми входящими файлами и дирами). |
|---|
| 126 |
function CheckFile(const ListFileName, RealFileName : AnsiString) : byte; //Проверить насколько реальный файл соответствует инфе в файле. Возвращает значение одной из констант Flist_CheckFile_*. Можно сравнивать директории. |
|---|
| 127 |
procedure CompareDirs(const ListDirName, RealDirName : AnsiString; var ComparedList : AComparedList); //Сравнить 2 папки, результат записывается в ComparedList. |
|---|
| 128 |
function CompareWithFlist(var OtherFlist : TFlistFormat; const ListDirName : AnsiString; var ComparedList : AComparedList) : boolean; //Сравнить текущий файл с другим, считая его (этот другой файл) как будто за текущую версию файлов на венте. |
|---|
| 129 |
function CompareWithFlist(const OtherFlistFile, ListDirName : AnsiString; var ComparedList : AComparedList) : boolean; //Сравнить текущий файл с другим, считая его (этот другой файл) как будто за текущую версию файлов на венте. |
|---|
| 130 |
function ConvertToSimpleComparedList(var ComparedList : AComparedList) : Boolean; //Превратить список сравнения в нечно упрощенное - без лишней инфы про то как именно что различается, когда важен сам факт наличия различия. |
|---|
| 131 |
procedure ParseUsedGroups(const GroupsStr : AnsiString); //Пропарсить строку с группами и забить инфу в объект. |
|---|
| 132 |
function GenUsedGroups : AnsiString; //Используя инфу в объекте сгенерить строку с группами. |
|---|
| 133 |
procedure UpdateUsedGroups; //Просмотреть список и сгенерировать новую инфу о группах, записать её в объект. |
|---|
| 134 |
end; |
|---|
| 135 |
|
|---|
| 136 |
//Функции в прямом, открытом виде %). |
|---|
| 137 |
function Flist_CheckFile_2Text(const Code : Byte) : AnsiString; //Сгенерить текстовую строку из кода Flist_CheckFile_* |
|---|
| 138 |
|
|---|
| 139 |
implementation |
|---|
| 140 |
|
|---|
| 141 |
///////////////////////////////////////////// |
|---|
| 142 |
// TFlistFormat // |
|---|
| 143 |
///////////////////////////////////////////// |
|---|
| 144 |
|
|---|
| 145 |
//-----------------------------------------// |
|---|
| 146 |
// Конструкторы-деструкторы... // |
|---|
| 147 |
//-----------------------------------------// |
|---|
| 148 |
|
|---|
| 149 |
constructor TFlistFormat.Create; |
|---|
| 150 |
begin |
|---|
| 151 |
//Создать вложенные объекты классов... |
|---|
| 152 |
UsedGroups := TStringList.Create; |
|---|
| 153 |
|
|---|
| 154 |
//Проставить дефолтные значения... |
|---|
| 155 |
Self.Clear(); |
|---|
| 156 |
ErrorMessage := 'none'; |
|---|
| 157 |
DoConsoleOutput := Flist_Def_DoConsoleOutput; |
|---|
| 158 |
end; |
|---|
| 159 |
|
|---|
| 160 |
destructor TFlistFormat.Destroy; |
|---|
| 161 |
begin |
|---|
| 162 |
//Выкидываем мусор |
|---|
| 163 |
SetLength(FileList,0); |
|---|
| 164 |
UsedGroups.Free; |
|---|
| 165 |
|
|---|
| 166 |
//Выполнить унаследованный деструктор |
|---|
| 167 |
inherited; |
|---|
| 168 |
end; |
|---|
| 169 |
|
|---|
| 170 |
//------------------------------------------// |
|---|
| 171 |
// Закрытые методы... // |
|---|
| 172 |
//------------------------------------------// |
|---|
| 173 |
|
|---|
| 174 |
function TFlistFormat.ParseFileType(const InputStr : AnsiString) : byte; |
|---|
| 175 |
//Вернуть код типа файла по строковому значению типа. |
|---|
| 176 |
begin |
|---|
| 177 |
if LowerCase(InputStr) = 'file' then begin |
|---|
| 178 |
//Файл |
|---|
| 179 |
Result := Flist_Filetype_File; |
|---|
| 180 |
end |
|---|
| 181 |
else if LowerCase(InputStr) = 'dir' then begin |
|---|
| 182 |
//Дира |
|---|
| 183 |
Result := Flist_Filetype_Directory; |
|---|
| 184 |
end |
|---|
| 185 |
else begin |
|---|
| 186 |
//хз-что |
|---|
| 187 |
Result := Flist_Filetype_Unknown; |
|---|
| 188 |
end; |
|---|
| 189 |
end; |
|---|
| 190 |
|
|---|
| 191 |
function TFlistFormat.ReturnFileTypeStr(const InputCode : byte) : AnsiString; |
|---|
| 192 |
//Наоборот сгенерить значение типа файла из кода. |
|---|
| 193 |
begin |
|---|
| 194 |
if InputCode = Flist_Filetype_File then begin |
|---|
| 195 |
//Файл |
|---|
| 196 |
Result := 'File'; |
|---|
| 197 |
end |
|---|
| 198 |
else if InputCode = Flist_Filetype_Directory then begin |
|---|
| 199 |
//Дира |
|---|
| 200 |
Result := 'Dir'; |
|---|
| 201 |
end |
|---|
| 202 |
else begin |
|---|
| 203 |
//хз-что |
|---|
| 204 |
Result := 'Unknown'; |
|---|
| 205 |
end; |
|---|
| 206 |
end; |
|---|
| 207 |
|
|---|
| 208 |
//------------------------------------------// |
|---|
| 209 |
// Открытые методы... // |
|---|
| 210 |
//------------------------------------------// |
|---|
| 211 |
|
|---|
| 212 |
function TFlistFormat.UseGroups : Boolean; |
|---|
| 213 |
//Используются ли группы файлов - возвращает значение, записать прямо его нельзя. |
|---|
| 214 |
begin |
|---|
| 215 |
Result := Self.ReallyUseGroups; |
|---|
| 216 |
end; |
|---|
| 217 |
|
|---|
| 218 |
procedure TFlistFormat.Clear(); |
|---|
| 219 |
//Очистить инфу класса. |
|---|
| 220 |
begin |
|---|
| 221 |
//Фактически - проставить дефолтные значения... |
|---|
| 222 |
PathsAreAbsolute := Flist_Def_PathsAreAbsolute; |
|---|
| 223 |
AddSize := Flist_Def_AddSize; |
|---|
| 224 |
AddCRC32 := Flist_Def_AddCRC32; |
|---|
| 225 |
FilesNum := 0; |
|---|
| 226 |
ReallyUseGroups := Flist_Def_UseGroups; |
|---|
| 227 |
Self.ParseUsedGroups(Flist_Def_UsedGroups); |
|---|
| 228 |
//Ну и массив в 0 элементов |
|---|
| 229 |
SetLength(FileList,0); |
|---|
| 230 |
//Другая служебная инфа. |
|---|
| 231 |
FileLoaded := false; |
|---|
| 232 |
LoadedFileName := ''; |
|---|
| 233 |
GlobalRoot := ''; |
|---|
| 234 |
end; |
|---|
| 235 |
|
|---|
| 236 |
function TFlistFormat.GetGlobalRoot() : AnsiString; |
|---|
| 237 |
//Вернуть корень. |
|---|
| 238 |
begin |
|---|
| 239 |
if Self.GlobalRoot = '' then begin |
|---|
| 240 |
//Если глобальный путь не указан. |
|---|
| 241 |
if Self.FileLoaded = true then begin |
|---|
| 242 |
//Если загружался какой-то файл - берем путь к этому файлу. |
|---|
| 243 |
Result := ExtractFilePath(Self.LoadedFileName); |
|---|
| 244 |
end |
|---|
| 245 |
else begin |
|---|
| 246 |
//Иначе берем путь к текущей дире. |
|---|
| 247 |
Result := GetCurrentDir(); |
|---|
| 248 |
end; |
|---|
| 249 |
end |
|---|
| 250 |
else begin |
|---|
| 251 |
//Если указан глобальный путь к корню - просто возвращаем его. |
|---|
| 252 |
Result := Self.GlobalRoot; |
|---|
| 253 |
end; |
|---|
| 254 |
end; |
|---|
| 255 |
|
|---|
| 256 |
function TFlistFormat.Load(const FileName : AnsiString) : boolean; |
|---|
| 257 |
//Загрузить инфу файла в класс. |
|---|
| 258 |
var |
|---|
| 259 |
AnIniFile : TAnIniFile; |
|---|
| 260 |
AllOk : boolean; |
|---|
| 261 |
IniValueList : AIniValueList; |
|---|
| 262 |
I, J, ReadVersion : Integer; |
|---|
| 263 |
|
|---|
| 264 |
begin |
|---|
| 265 |
//Инициализация. |
|---|
| 266 |
AnIniFile := TAnIniFile.Create; |
|---|
| 267 |
SetLength(IniValueList,0,0); //Инициализация пустого динамического массива для инфы секции [Files] |
|---|
| 268 |
Result := false; |
|---|
| 269 |
if Self.DoConsoleOutput = true then begin |
|---|
| 270 |
Writeln(_('Loading file ')+FileName+' ... '); |
|---|
| 271 |
end; |
|---|
| 272 |
|
|---|
| 273 |
//Очистка инфы класса... |
|---|
| 274 |
Self.Clear(); |
|---|
| 275 |
|
|---|
| 276 |
//Собсно грузим... |
|---|
| 277 |
AllOk := FileExists(FileName); |
|---|
| 278 |
if AllOk = false then begin |
|---|
| 279 |
//Если файла не существует... |
|---|
| 280 |
ErrorMessage := _('File ')+FileName+_(' is not exists.'); |
|---|
| 281 |
end |
|---|
| 282 |
else begin |
|---|
| 283 |
//Если сам файлик вообще существует... Загружаем... |
|---|
| 284 |
AllOk := AnIniFile.Load(FileName); |
|---|
| 285 |
if AllOk = false then begin |
|---|
| 286 |
//Не удалось загрузить файл. |
|---|
| 287 |
ErrorMessage := _('Error, loading file ')+FileName; |
|---|
| 288 |
end; |
|---|
| 289 |
end; |
|---|
| 290 |
|
|---|
| 291 |
if AllOk = true then begin |
|---|
| 292 |
//Ок, загружено. Читаем сигнатуру... |
|---|
| 293 |
if AnIniFile.ReadString('Main', 'FormatName') <> 'FileList' then begin |
|---|
| 294 |
//Это не FileList-файл. |
|---|
| 295 |
AllOk := false; |
|---|
| 296 |
ErrorMessage := _('File ')+FileName+_(' is not FileList file.'); |
|---|
| 297 |
end; |
|---|
| 298 |
end; |
|---|
| 299 |
|
|---|
| 300 |
if AllOk = true then begin |
|---|
| 301 |
//Проверяем версию формата... |
|---|
| 302 |
ReadVersion := AnIniFile.ReadInteger('Main', 'FormatVersion'); |
|---|
| 303 |
if ReadVersion > Flist_FormatVersion then begin |
|---|
| 304 |
//Формат более новой версии чем код в бинарнике. |
|---|
| 305 |
AllOk := false; |
|---|
| 306 |
ErrorMessage := _('File ')+FileName+_(' has more new version (')+IntToStr(ReadVersion)+_(') then i know (')+IntToStr(Flist_FormatVersion)+_('). Aborted loading. Try update to a new version of this software.'); |
|---|
| 307 |
end |
|---|
| 308 |
else if ReadVersion < Flist_FormatVersion then begin |
|---|
| 309 |
//Загруженный файлик более старой версии - надо его обновить. |
|---|
| 310 |
if ReadVersion = 1 then begin |
|---|
| 311 |
// 1 -> 2. |
|---|
| 312 |
//[Main] |
|---|
| 313 |
AnIniFile.WriteBool('Main','UseGroups',Flist_Def_UseGroups); |
|---|
| 314 |
AnIniFile.WriteString('Main','UsedGroups',Flist_Def_UsedGroups); |
|---|
| 315 |
AnIniFile.WriteInteger('Main', 'FormatVersion',2); |
|---|
| 316 |
end; |
|---|
| 317 |
end; |
|---|
| 318 |
end; |
|---|
| 319 |
|
|---|
| 320 |
if AllOk = true then begin |
|---|
| 321 |
//Собсно читаем инфу... |
|---|
| 322 |
|
|---|
| 323 |
//[Main] |
|---|
| 324 |
PathsAreAbsolute := AnIniFile.ReadBool('Main','PathsAreAbsolute'); |
|---|
| 325 |
AddSize := AnIniFile.ReadBool('Main','AddSize'); |
|---|
| 326 |
AddCRC32 := AnIniFile.ReadBool('Main','AddCRC32'); |
|---|
| 327 |
//FilesNum := AnIniFile.ReadInteger('Main','FilesNum'); //Ненужно, важнее реальное количество в списке. |
|---|
| 328 |
ReallyUseGroups := AnIniFile.ReadBool('Main','UseGroups'); |
|---|
| 329 |
Self.ParseUsedGroups(AnIniFile.ReadString('Main','UsedGroups')); |
|---|
| 330 |
//[Files] |
|---|
| 331 |
AnIniFile.ReadIniValueList('Files',IniValueList); //Читаем секцию... |
|---|
| 332 |
//Заносим инфу о количестве файлов... |
|---|
| 333 |
FilesNum := Length(IniValueList); |
|---|
| 334 |
//Выделяем память под файлы... |
|---|
| 335 |
SetLength(FileList,FilesNum); |
|---|
| 336 |
//И собсно парсим... |
|---|
| 337 |
if FilesNum > 0 then begin |
|---|
| 338 |
//Если собсно есть что парсить. |
|---|
| 339 |
for I := 0 to FilesNum-1 do begin |
|---|
| 340 |
for J := 0 to Length(IniValueList[I])-1 do begin |
|---|
| 341 |
//По элементам. |
|---|
| 342 |
if IniValueList[I,J].Name = 'File' then begin |
|---|
| 343 |
FileList[I].FilePath := IniValueList[I,J].Value; |
|---|
| 344 |
end |
|---|
| 345 |
else if IniValueList[I,J].Name = 'Type' then begin |
|---|
| 346 |
FileList[I].FileType := ParseFileType(IniValueList[I,J].Value); |
|---|
| 347 |
end |
|---|
| 348 |
else if IniValueList[I,J].Name = 'Size' then begin |
|---|
| 349 |
FileList[I].FileSize := StrToInt(IniValueList[I,J].Value); |
|---|
| 350 |
end |
|---|
| 351 |
else if IniValueList[I,J].Name = 'CRC32' then begin |
|---|
| 352 |
FileList[I].CRC32 := StrToInt('$'+IniValueList[I,J].Value); //Знак доллара - т.к. читается число в виде HEX. |
|---|
| 353 |
end |
|---|
| 354 |
else if IniValueList[I,J].Name = 'Group' then begin |
|---|
| 355 |
FileList[I].Group := IniValueList[I,J].Value; |
|---|
| 356 |
end |
|---|
| 357 |
end; |
|---|
| 358 |
//Если используются группы - убедиться что файлу пробита группа. |
|---|
| 359 |
if Self.UseGroups = true then begin |
|---|
| 360 |
if Length(FileList[I].Group) = 0 then begin |
|---|
| 361 |
//Пусто - вбиваем "all" |
|---|
| 362 |
FileList[I].Group := 'all'; |
|---|
| 363 |
end; |
|---|
| 364 |
end; |
|---|
| 365 |
end; |
|---|
| 366 |
end; |
|---|
| 367 |
|
|---|
| 368 |
//Ну, вроде бы все что надо прочитано. Теперь отмечаем что фсеок и собсно все. |
|---|
| 369 |
Result := true; |
|---|
| 370 |
if Self.DoConsoleOutput = true then begin |
|---|
| 371 |
Writeln(_('Loaded file ')+FileName); |
|---|
| 372 |
end; |
|---|
| 373 |
FileLoaded := true; |
|---|
| 374 |
LoadedFileName := FileName; |
|---|
| 375 |
end; |
|---|
| 376 |
|
|---|
| 377 |
//Уборка мусора. |
|---|
| 378 |
AnIniFile.Free; |
|---|
| 379 |
SetLength(IniValueList,0,0); |
|---|
| 380 |
end; |
|---|
| 381 |
|
|---|
| 382 |
function TFlistFormat.Save(const FileName : AnsiString) : boolean; |
|---|
| 383 |
//Сохранить инфу из класса в файл. |
|---|
| 384 |
var |
|---|
| 385 |
AnIniFile : TAnIniFile; |
|---|
| 386 |
I, J, ValElemNum : Integer; |
|---|
| 387 |
IniValueList : AIniValueList; |
|---|
| 388 |
|
|---|
| 389 |
begin |
|---|
| 390 |
//Инициализация. |
|---|
| 391 |
AnIniFile := TAnIniFile.Create; |
|---|
| 392 |
SetLength(IniValueList,0,0); |
|---|
| 393 |
Result := false; |
|---|
| 394 |
if Self.DoConsoleOutput = true then begin |
|---|
| 395 |
Writeln(_('Saving file ')+FileName+' ... '); |
|---|
| 396 |
end; |
|---|
| 397 |
|
|---|
| 398 |
//Крейтим новое файло... |
|---|
| 399 |
AnIniFile.MakNewFile; |
|---|
| 400 |
//Закидываем инфу... |
|---|
| 401 |
//[Main] |
|---|
| 402 |
AnIniFile.WriteString('Main', 'FormatName', 'FileList'); |
|---|
| 403 |
AnIniFile.WriteInteger('Main', 'FormatVersion', Flist_FormatVersion); |
|---|
| 404 |
AnIniFile.WriteBool('Main', 'PathsAreAbsolute', PathsAreAbsolute); |
|---|
| 405 |
AnIniFile.WriteBool('Main', 'AddSize', AddSize); |
|---|
| 406 |
AnIniFile.WriteBool('Main', 'AddCRC32', AddCRC32); |
|---|
| 407 |
AnIniFile.WriteInteger('Main', 'FilesNum', FilesNum); |
|---|
| 408 |
AnIniFile.WriteBool('Main', 'UseGroups', UseGroups); |
|---|
| 409 |
AnIniFile.WriteString('Main', 'UsedGroups', GenUsedGroups); |
|---|
| 410 |
|
|---|
| 411 |
//[Files] |
|---|
| 412 |
//Определить сколько элементов будет в каждой "строке" IniValueList |
|---|
| 413 |
ValElemNum := 2; //Минимум. |
|---|
| 414 |
if AddSize = true then ValElemNum := ValElemNum+1; |
|---|
| 415 |
if AddCRC32 = true then ValElemNum := ValElemNum+1; |
|---|
| 416 |
if UseGroups = true then ValElemNum := ValElemNum+1; |
|---|
| 417 |
//Выделить память под элементы IniValueList |
|---|
| 418 |
SetLength(IniValueList,FilesNum,ValElemNum); |
|---|
| 419 |
//Закинуть всю инфу по файлам в IniValueList |
|---|
| 420 |
for I := 0 to FilesNum-1 do begin |
|---|
| 421 |
J := 0; |
|---|
| 422 |
//File |
|---|
| 423 |
IniValueList[I,J].Name := 'File'; |
|---|
| 424 |
IniValueList[I,J].Value := FileList[I].FilePath; |
|---|
| 425 |
J := J+1; |
|---|
| 426 |
//Type |
|---|
| 427 |
IniValueList[I,J].Name := 'Type'; |
|---|
| 428 |
IniValueList[I,J].Value := ReturnFileTypeStr(FileList[I].FileType); |
|---|
| 429 |
J := J+1; |
|---|
| 430 |
//Size |
|---|
| 431 |
if AddSize = true then begin |
|---|
| 432 |
IniValueList[I,J].Name := 'Size'; |
|---|
| 433 |
IniValueList[I,J].Value := IntToStr(FileList[I].FileSize); |
|---|
| 434 |
J := J+1; |
|---|
| 435 |
end; |
|---|
| 436 |
//CRC32 |
|---|
| 437 |
if AddCRC32 = true then begin |
|---|
| 438 |
IniValueList[I,J].Name := 'CRC32'; |
|---|
| 439 |
IniValueList[I,J].Value := IntToHex(FileList[I].CRC32,8); |
|---|
| 440 |
end; |
|---|
| 441 |
//Group |
|---|
| 442 |
if UseGroups = true then begin |
|---|
| 443 |
IniValueList[I,J].Name := 'Group'; |
|---|
| 444 |
IniValueList[I,J].Value := FileList[I].Group; |
|---|
| 445 |
end; |
|---|
| 446 |
end; |
|---|
| 447 |
//Записать сгенеренный список в секцию... |
|---|
| 448 |
AnIniFile.WriteIniValueList('Files',IniValueList); |
|---|
| 449 |
|
|---|
| 450 |
//Терь можно сохранить файл... |
|---|
| 451 |
Result := AnIniFile.Save(FileName); |
|---|
| 452 |
//Если сохранилось удачно - запоминаем чего там за файлег. |
|---|
| 453 |
if Result = true then begin |
|---|
| 454 |
FileLoaded := true; |
|---|
| 455 |
LoadedFileName := FileName; |
|---|
| 456 |
if Self.DoConsoleOutput = true then begin |
|---|
| 457 |
Writeln(_('Saved file ')+FileName); |
|---|
| 458 |
end; |
|---|
| 459 |
end; |
|---|
| 460 |
|
|---|
| 461 |
//Выкидываем хлам (ака мусор). |
|---|
| 462 |
AnIniFile.Free; |
|---|
| 463 |
SetLength(IniValueList,0,0); |
|---|
| 464 |
end; |
|---|
| 465 |
|
|---|
| 466 |
function TFlistFormat.ElementNameExists(const ElementName : AnsiString) : boolean; |
|---|
| 467 |
//Существует ли элемент с таким именем. |
|---|
| 468 |
var |
|---|
| 469 |
I : Integer; |
|---|
| 470 |
TempElemName : AnsiString; |
|---|
| 471 |
|
|---|
| 472 |
begin |
|---|
| 473 |
//Инициализация. |
|---|
| 474 |
Result := false; |
|---|
| 475 |
I := -1; |
|---|
| 476 |
TempElemName := UpperCase(DelLastSlash(ElementName)); |
|---|
| 477 |
|
|---|
| 478 |
//Пробежаться по массиву с файлами пока элемент не будет найден или пока массив не закончится. |
|---|
| 479 |
repeat |
|---|
| 480 |
|
|---|
| 481 |
I := I+1; |
|---|
| 482 |
//Итак, независимо от того что это - папка ли, файл ли - смотрим. |
|---|
| 483 |
if UpperCase(DelLastSlash(FileList[I].FilePath)) = TempElemName then begin |
|---|
| 484 |
Result := true; //Все, нашли, из цикла оно терь вылетит и вернется true. |
|---|
| 485 |
end; |
|---|
| 486 |
|
|---|
| 487 |
until (Result = true) or (I = FilesNum-1); |
|---|
| 488 |
|
|---|
| 489 |
end; |
|---|
| 490 |
|
|---|
| 491 |
function TFlistFormat.GetElementNumber(const ElementName : AnsiString) : Integer; |
|---|
| 492 |
//Какой номер у элемента с таким именем. |
|---|
| 493 |
var |
|---|
| 494 |
I : Integer; |
|---|
| 495 |
TempElemName : AnsiString; |
|---|
| 496 |
|
|---|
| 497 |
begin |
|---|
| 498 |
//Инициализация. |
|---|
| 499 |
Result := -1; |
|---|
| 500 |
I := -1; |
|---|
| 501 |
TempElemName := UpperCase(DelLastSlash(ElementName)); |
|---|
| 502 |
|
|---|
| 503 |
//Пробежаться по массиву с файлами пока элемент не будет найден или пока массив не закончится. |
|---|
| 504 |
repeat |
|---|
| 505 |
|
|---|
| 506 |
I := I+1; |
|---|
| 507 |
//Итак, независимо от того что это - папка ли, файл ли - смотрим. |
|---|
| 508 |
if UpperCase(DelLastSlash(FileList[I].FilePath)) = TempElemName then begin |
|---|
| 509 |
Result := I; //Все, нашли, из цикла оно терь вылетит и вернется true. |
|---|
| 510 |
end; |
|---|
| 511 |
|
|---|
| 512 |
until (Result = I) or (I = FilesNum-1); |
|---|
| 513 |
|
|---|
| 514 |
end; |
|---|
| 515 |
|
|---|
| 516 |
function TFlistFormat.FileExistsHere(const FileName : AnsiString) : boolean; |
|---|
| 517 |
//Существует ли файл с таким именем. |
|---|
| 518 |
var |
|---|
| 519 |
I : Integer; |
|---|
| 520 |
TempFileName : AnsiString; |
|---|
| 521 |
|
|---|
| 522 |
begin |
|---|
| 523 |
//Инициализация. |
|---|
| 524 |
Result := false; |
|---|
| 525 |
I := -1; |
|---|
| 526 |
TempFileName := UpperCase(FileName); |
|---|
| 527 |
|
|---|
| 528 |
//Пробежаться по массиву с файлами пока элемент не будет найден или пока массив не закончится. |
|---|
| 529 |
repeat |
|---|
| 530 |
|
|---|
| 531 |
I := I+1; |
|---|
| 532 |
|
|---|
| 533 |
if FileList[I].FileType = Flist_Filetype_File then begin |
|---|
| 534 |
//Только если это файло. |
|---|
| 535 |
if UpperCase(FileList[I].FilePath) = TempFileName then begin |
|---|
| 536 |
Result := true; //Все, нашли, из цикла оно терь вылетит и вернется true. |
|---|
| 537 |
end; |
|---|
| 538 |
end; |
|---|
| 539 |
|
|---|
| 540 |
until (Result = true) or (I = FilesNum-1); |
|---|
| 541 |
|
|---|
| 542 |
end; |
|---|
| 543 |
|
|---|
| 544 |
function TFlistFormat.GetFileNumberHere(const FileName : AnsiString) : Integer; |
|---|
| 545 |
//Какой номер у файла с таким именем. |
|---|
| 546 |
var |
|---|
| 547 |
I : Integer; |
|---|
| 548 |
TempFileName : AnsiString; |
|---|
| 549 |
|
|---|
| 550 |
begin |
|---|
| 551 |
//Инициализация. |
|---|
| 552 |
Result := -1; |
|---|
| 553 |
I := -1; |
|---|
| 554 |
TempFileName := UpperCase(FileName); |
|---|
| 555 |
|
|---|
| 556 |
//Пробежаться по массиву с файлами пока элемент не будет найден или пока массив не закончится. |
|---|
| 557 |
repeat |
|---|
| 558 |
|
|---|
| 559 |
I := I+1; |
|---|
| 560 |
|
|---|
| 561 |
if FileList[I].FileType = Flist_Filetype_File then begin |
|---|
| 562 |
//Только если это файло. |
|---|
| 563 |
if UpperCase(FileList[I].FilePath) = TempFileName then begin |
|---|
| 564 |
Result := I; //Все, нашли, из цикла оно терь вылетит и вернется true. |
|---|
| 565 |
end; |
|---|
| 566 |
end; |
|---|
| 567 |
|
|---|
| 568 |
until (Result = I) or (I = FilesNum-1); |
|---|
| 569 |
|
|---|
| 570 |
end; |
|---|
| 571 |
|
|---|
| 572 |
function TFlistFormat.DirExistsHere(const DirName : AnsiString) : boolean; |
|---|
| 573 |
//Существует ли дира с таким именем. |
|---|
| 574 |
var |
|---|
| 575 |
I : Integer; |
|---|
| 576 |
TempDirName : AnsiString; |
|---|
| 577 |
|
|---|
| 578 |
begin |
|---|
| 579 |
//Инициализация. |
|---|
| 580 |
Result := false; |
|---|
| 581 |
I := -1; |
|---|
| 582 |
TempDirName := DelLastSlash(UpperCase(DirName)); |
|---|
| 583 |
|
|---|
| 584 |
//Пробежаться по массиву с файлами пока элемент не будет найден или пока массив не закончится. |
|---|
| 585 |
repeat |
|---|
| 586 |
|
|---|
| 587 |
I := I+1; |
|---|
| 588 |
|
|---|
| 589 |
if FileList[I].FileType = Flist_Filetype_Directory then begin |
|---|
| 590 |
//Только если это дира. |
|---|
| 591 |
if UpperCase(DelLastSlash(FileList[I].FilePath)) = TempDirName then begin |
|---|
| 592 |
Result := true; //Все, нашли, из цикла оно терь вылетит и вернется true. |
|---|
| 593 |
end; |
|---|
| 594 |
end; |
|---|
| 595 |
|
|---|
| 596 |
until (Result = true) or (I = FilesNum-1); |
|---|
| 597 |
|
|---|
| 598 |
end; |
|---|
| 599 |
|
|---|
| 600 |
function TFlistFormat.GetDirNumberHere(const DirName : AnsiString) : Integer; |
|---|
| 601 |
//Определить номер диры с таким именем. |
|---|
| 602 |
var |
|---|
| 603 |
I : Integer; |
|---|
| 604 |
TempDirName : AnsiString; |
|---|
| 605 |
|
|---|
| 606 |
begin |
|---|
| 607 |
//Инициализация. |
|---|
| 608 |
Result := -1; |
|---|
| 609 |
I := -1; |
|---|
| 610 |
TempDirName := DelLastSlash(UpperCase(DirName)); |
|---|
| 611 |
|
|---|
| 612 |
//Пробежаться по массиву с файлами пока элемент не будет найден или пока массив не закончится. |
|---|
| 613 |
repeat |
|---|
| 614 |
|
|---|
| 615 |
I := I+1; |
|---|
| 616 |
|
|---|
| 617 |
if FileList[I].FileType = Flist_Filetype_Directory then begin |
|---|
| 618 |
//Только если это дира. |
|---|
| 619 |
if UpperCase(DelLastSlash(FileList[I].FilePath)) = TempDirName then begin |
|---|
| 620 |
Result := I; //Все, нашли, из цикла оно терь вылетит и вернется true. |
|---|
| 621 |
end; |
|---|
| 622 |
end; |
|---|
| 623 |
|
|---|
| 624 |
until (Result = I) or (I = FilesNum-1); |
|---|
| 625 |
|
|---|
| 626 |
end; |
|---|
| 627 |
|
|---|
| 628 |
function TFlistFormat.GetRealElementName(const ElemName : AnsiString) : AnsiString; |
|---|
| 629 |
//Определить абсолютное имя для элемента |
|---|
| 630 |
begin |
|---|
| 631 |
//Получаем абсолютный путь.... |
|---|
| 632 |
if IsLocalPath(ElemName) = true then begin |
|---|
| 633 |
//Если надо генерить - генерим. |
|---|
| 634 |
Result := ResolveLocalPath(ElemName,Self.GetGlobalRoot()); |
|---|
| 635 |
end |
|---|
| 636 |
else begin |
|---|
| 637 |
//Он уже глобальный. |
|---|
| 638 |
Result := ElemName; |
|---|
| 639 |
end; |
|---|
| 640 |
end; |
|---|
| 641 |
|
|---|
| 642 |
function TFlistFormat.GetRealElementName(const ElemNum : Integer) : AnsiString; |
|---|
| 643 |
//Определить абсолютное имя для элемента с таким-то номером в списке. |
|---|
| 644 |
begin |
|---|
| 645 |
//Просто вызываем функцию выше с именем элемента... |
|---|
| 646 |
Result := GetRealElementName(Self.FileList[ElemNum].FilePath); |
|---|
| 647 |
end; |
|---|
| 648 |
|
|---|
| 649 |
function TFlistFormat.AddFile(const FileName : AnsiString) : boolean; |
|---|
| 650 |
//Добавить файл. |
|---|
| 651 |
var |
|---|
| 652 |
CurrFileNum : Integer; |
|---|
| 653 |
LocalName, GlobalName : AnsiString; |
|---|
| 654 |
|
|---|
| 655 |
begin |
|---|
| 656 |
//Инициализация. |
|---|
| 657 |
Result := false; |
|---|
| 658 |
CurrFileNum := FilesNum; //После добавления нового файла эта цифра будет номером последнего элемента массива. |
|---|
| 659 |
|
|---|
| 660 |
//Увеличить размер массива на один. |
|---|
| 661 |
FilesNum := FilesNum+1; |
|---|
| 662 |
SetLength(FileList,FilesNum); |
|---|
| 663 |
|
|---|
| 664 |
//Получаем абсолютный путь.... |
|---|
| 665 |
if IsLocalPath(FileName) = true then begin |
|---|
| 666 |
//Если надо генерить - генерим. |
|---|
| 667 |
GlobalName := ResolveLocalPath(FileName,Self.GetGlobalRoot()); |
|---|
| 668 |
end |
|---|
| 669 |
else begin |
|---|
| 670 |
//Он уже глобальный. |
|---|
| 671 |
GlobalName := FileName; |
|---|
| 672 |
end; |
|---|
| 673 |
|
|---|
| 674 |
//Если нужно - получаем относительный путь. |
|---|
| 675 |
if Self.PathsAreAbsolute = false then begin |
|---|
| 676 |
LocalName := GetLocalPath(Self.GetGlobalRoot(),GlobalName); |
|---|
| 677 |
end; |
|---|
| 678 |
|
|---|
| 679 |
//Забить параметры для файла. |
|---|
| 680 |
//FilePath |
|---|
| 681 |
if Self.PathsAreAbsolute = true then begin |
|---|
| 682 |
//Имя должно быть абсолютное. |
|---|
| 683 |
FileList[CurrFileNum].FilePath := GlobalName; |
|---|
| 684 |
end |
|---|
| 685 |
else begin |
|---|
| 686 |
//Имя должно быть относительное |
|---|
| 687 |
FileList[CurrFileNum].FilePath := LocalName; |
|---|
| 688 |
end; |
|---|
| 689 |
//FileType |
|---|
| 690 |
FileList[CurrFileNum].FileType := Flist_Filetype_File; |
|---|
| 691 |
//FileSize |
|---|
| 692 |
if Self.AddSize = true then begin |
|---|
| 693 |
FileList[CurrFileNum].FileSize := 0; |
|---|
| 694 |
end; |
|---|
| 695 |
//CRC32 |
|---|
| 696 |
if Self.AddCRC32 = true then begin |
|---|
| 697 |
FileList[CurrFileNum].CRC32 := crc32(0, nil, 0); //Получится "пустое" значение CRC32. |
|---|
| 698 |
end; |
|---|
| 699 |
|
|---|
| 700 |
//Вернуть результат. |
|---|
| 701 |
Result := true; |
|---|
| 702 |
end; |
|---|
| 703 |
|
|---|
| 704 |
function TFlistFormat.AddRealFile(const FileName : AnsiString) : boolean; |
|---|
| 705 |
//Добавить реально существующий на диске файл (с подсчетом реальной инфы). |
|---|
| 706 |
var |
|---|
| 707 |
CurrFileNum : Integer; |
|---|
| 708 |
LocalName, GlobalName : AnsiString; |
|---|
| 709 |
|
|---|
| 710 |
begin |
|---|
| 711 |
//Код независит от функции TFlistFormat.AddFile в целях более оптимальной работы. |
|---|
| 712 |
//Инициализация. |
|---|
| 713 |
Result := false; |
|---|
| 714 |
CurrFileNum := FilesNum; //После добавления нового файла эта цифра будет номером последнего элемента массива. |
|---|
| 715 |
|
|---|
| 716 |
//Получаем абсолютный путь.... |
|---|
| 717 |
if IsLocalPath(FileName) = true then begin |
|---|
| 718 |
//Если надо генерить - генерим. |
|---|
| 719 |
GlobalName := ResolveLocalPath(FileName,Self.GetGlobalRoot()); |
|---|
| 720 |
end |
|---|
| 721 |
else begin |
|---|
| 722 |
//Он уже глобальный. |
|---|
| 723 |
GlobalName := FileName; |
|---|
| 724 |
end; |
|---|
| 725 |
|
|---|
| 726 |
//Если нужно - получаем относительный путь. |
|---|
| 727 |
if Self.PathsAreAbsolute = false then begin |
|---|
| 728 |
LocalName := GetLocalPath(Self.GetGlobalRoot(),GlobalName); |
|---|
| 729 |
end; |
|---|
| 730 |
|
|---|
| 731 |
//Увеличить размер массива на один. |
|---|
| 732 |
FilesNum := FilesNum+1; |
|---|
| 733 |
SetLength(FileList,FilesNum); |
|---|
| 734 |
|
|---|
| 735 |
//Забить параметры для файла. |
|---|
| 736 |
//FilePath |
|---|
| 737 |
if Self.PathsAreAbsolute = true then begin |
|---|
| 738 |
//Имя должно быть абсолютное. |
|---|
| 739 |
FileList[CurrFileNum].FilePath := GlobalName; |
|---|
| 740 |
end |
|---|
| 741 |
else begin |
|---|
| 742 |
//Имя должно быть относительное |
|---|
| 743 |
FileList[CurrFileNum].FilePath := LocalName; |
|---|
| 744 |
end; |
|---|
| 745 |
//FileType |
|---|
| 746 |
FileList[CurrFileNum].FileType := Flist_Filetype_File; |
|---|
| 747 |
//FileSize |
|---|
| 748 |
if Self.AddSize = true then begin |
|---|
| 749 |
FileList[CurrFileNum].FileSize := GetFileSize(GlobalName); //Подсчитать размер. Если файла нету - вернет нолик. |
|---|
| 750 |
end; |
|---|
| 751 |
//CRC32 |
|---|
| 752 |
if Self.AddCRC32 = true then begin |
|---|
| 753 |
FileList[CurrFileNum].CRC32 := FileToCRC32(GlobalName,DoConsoleOutput); //Подсчитать CRC32 для файла. Если файла нету - будет "пустое" значение. |
|---|
| 754 |
end; |
|---|
| 755 |
|
|---|
| 756 |
//Вернуть результат. |
|---|
| 757 |
Result := true; |
|---|
| 758 |
end; |
|---|
| 759 |
|
|---|
| 760 |
function TFlistFormat.AddDirectory(const DirName : AnsiString) : boolean; |
|---|
| 761 |
//Добавить пустую диру. |
|---|
| 762 |
var |
|---|
| 763 |
CurrFileNum : Integer; |
|---|
| 764 |
LocalName, GlobalName : AnsiString; |
|---|
| 765 |
|
|---|
| 766 |
begin |
|---|
| 767 |
//Инициализация. |
|---|
| 768 |
Result := false; |
|---|
| 769 |
CurrFileNum := FilesNum; //После добавления новой диры эта цифра будет номером последнего элемента массива. |
|---|
| 770 |
|
|---|
| 771 |
//Увеличить размер массива на один. |
|---|
| 772 |
FilesNum := FilesNum+1; |
|---|
| 773 |
SetLength(FileList,FilesNum); |
|---|
| 774 |
|
|---|
| 775 |
//Получаем абсолютный путь.... |
|---|
| 776 |
if IsLocalPath(DirName) = true then begin |
|---|
| 777 |
//Если надо генерить - генерим. |
|---|
| 778 |
GlobalName := DelLastSlash(ResolveLocalPath(DirName,Self.GetGlobalRoot())); |
|---|
| 779 |
end |
|---|
| 780 |
else begin |
|---|
| 781 |
//Он уже глобальный. |
|---|
| 782 |
GlobalName := DelLastSlash(DirName); |
|---|
| 783 |
end; |
|---|
| 784 |
|
|---|
| 785 |
//Если нужно - получаем относительный путь. |
|---|
| 786 |
if Self.PathsAreAbsolute = false then begin |
|---|
| 787 |
LocalName := GetLocalPath(Self.GetGlobalRoot(),GlobalName); |
|---|
| 788 |
end; |
|---|
| 789 |
|
|---|
| 790 |
//Забить параметры для диры. |
|---|
| 791 |
//FilePath |
|---|
| 792 |
if Self.PathsAreAbsolute = true then begin |
|---|
| 793 |
//Имя должно быть абсолютное. |
|---|
| 794 |
FileList[CurrFileNum].FilePath := GlobalName; |
|---|
| 795 |
end |
|---|
| 796 |
else begin |
|---|
| 797 |
//Имя должно быть относительное |
|---|
| 798 |
FileList[CurrFileNum].FilePath := LocalName; |
|---|
| 799 |
end; |
|---|
| 800 |
//FileType |
|---|
| 801 |
FileList[CurrFileNum].FileType := Flist_Filetype_Directory; |
|---|
| 802 |
|
|---|
| 803 |
//Вернуть результат. |
|---|
| 804 |
Result := true; |
|---|
| 805 |
end; |
|---|
| 806 |
|
|---|
| 807 |
function TFlistFormat.AddRealDirectory(const DirName : AnsiString; const Recursive : boolean) : boolean; |
|---|
| 808 |
//Добавить реальную диру с подсчетом всей инфы по файлам. |
|---|
| 809 |
var |
|---|
| 810 |
AddingFiles : LongInt; |
|---|
| 811 |
LocalName, GlobalName : AnsiString; |
|---|
| 812 |
|
|---|
| 813 |
function ReallyAddDirectory(const DirName : AnsiString; const Recursive : boolean) : boolean; |
|---|
| 814 |
//Функция, непосредственно читающая инфу по директории... |
|---|
| 815 |
var |
|---|
| 816 |
SearchRec : TSearchRec; |
|---|
| 817 |
LocalDirName : AnsiString; |
|---|
| 818 |
begin |
|---|
| 819 |
//Инициализация. |
|---|
| 820 |
Result := true; |
|---|
| 821 |
|
|---|
| 822 |
//Если нужно - получаем относительный путь. |
|---|
| 823 |
if Self.PathsAreAbsolute = false then begin |
|---|
| 824 |
LocalDirName := GetLocalPath(Self.GetGlobalRoot(),DirName); |
|---|
| 825 |
end; |
|---|
| 826 |
|
|---|
| 827 |
//Начать сбор инфы... |
|---|
| 828 |
if FindFirst(AddLastSlash(DirName)+'*', faAnyFile and faDirectory, SearchRec) = 0 then begin |
|---|
| 829 |
//Если поиск успешно начат. |
|---|
| 830 |
repeat |
|---|
| 831 |
//Повторяем поиск пока не закончится то что можно искать %). |
|---|
| 832 |
if (SearchRec.Name <> '.') and (SearchRec.Name <> '..') then begin |
|---|
| 833 |
//Чего-то нашли. |
|---|
| 834 |
if (SearchRec.Attr and faDirectory) <> faDirectory then begin |
|---|
| 835 |
//Ход мыслей прост. Если то что мы нашли не директория - значит это файл %). Ибо проверять |
|---|
| 836 |
//по принципу "файл ли это" опасно - директория - она тоже файл %). |
|---|
| 837 |
//Итак, то что нашли - файл. Добавляем. |
|---|
| 838 |
|
|---|
| 839 |
//Забить параметры для файла. |
|---|
| 840 |
//FilePath |
|---|
| 841 |
if Self.PathsAreAbsolute = true then begin |
|---|
| 842 |
//Имя должно быть абсолютное. |
|---|
| 843 |
FileList[FilesNum].FilePath := AddLastSlash(DirName)+SearchRec.Name; |
|---|
| 844 |
end |
|---|
| 845 |
else begin |
|---|
| 846 |
//Имя должно быть относительное |
|---|
| 847 |
FileList[FilesNum].FilePath := AddLastSlash(LocalDirName)+SearchRec.Name; |
|---|
| 848 |
end; |
|---|
| 849 |
//FileType |
|---|
| 850 |
FileList[FilesNum].FileType := Flist_Filetype_File; |
|---|
| 851 |
//FileSize |
|---|
| 852 |
if Self.AddSize = true then begin |
|---|
| 853 |
try |
|---|
| 854 |
FileList[FilesNum].FileSize := GetFileSize(AddLastSlash(DirName)+SearchRec.Name); //Подсчитать размер. Если файла нету - вернет нолик. |
|---|
| 855 |
except |
|---|
| 856 |
Self.ErrorMessage := _('Can''t calc file size for ')+AddLastSlash(DirName)+SearchRec.Name; |
|---|
| 857 |
Result := false; |
|---|
| 858 |
Break; |
|---|
| 859 |
end; |
|---|
| 860 |
end; |
|---|
| 861 |
//CRC32 |
|---|
| 862 |
if Self.AddCRC32 = true then begin |
|---|
| 863 |
try |
|---|
| 864 |
FileList[FilesNum].CRC32 := FileToCRC32(AddLastSlash(DirName)+SearchRec.Name,DoConsoleOutput); //Подсчитать CRC32 для файла. Если файла нету - будет "пустое" значение. |
|---|
| 865 |
except |
|---|
| 866 |
Self.ErrorMessage := _('Can''t calc CRC32 for ')+AddLastSlash(DirName)+SearchRec.Name; |
|---|
| 867 |
Result := false; |
|---|
| 868 |
Break; |
|---|
| 869 |
end; |
|---|
| 870 |
end; |
|---|
| 871 |
|
|---|
| 872 |
//+1 счетчик файлов в массиве с инфой. |
|---|
| 873 |
FilesNum := FilesNum+1; |
|---|
| 874 |
|
|---|
| 875 |
end |
|---|
| 876 |
else begin |
|---|
| 877 |
//Если то что нашли - директория. Аналогично - добавляем... |
|---|
| 878 |
|
|---|
| 879 |
//Забить параметры для диры. |
|---|
| 880 |
//FilePath |
|---|
| 881 |
if Self.PathsAreAbsolute = true then begin |
|---|
| 882 |
//Имя должно быть абсолютное. |
|---|
| 883 |
FileList[FilesNum].FilePath := AddLastSlash(DirName)+SearchRec.Name; |
|---|
| 884 |
end |
|---|
| 885 |
else begin |
|---|
| 886 |
//Имя должно быть относительное |
|---|
| 887 |
FileList[FilesNum].FilePath := AddLastSlash(LocalDirName)+SearchRec.Name; |
|---|
| 888 |
end; |
|---|
| 889 |
//FileType |
|---|
| 890 |
FileList[FilesNum].FileType := Flist_Filetype_Directory; |
|---|
| 891 |
|
|---|
| 892 |
//+1 счетчик файлов в массиве с инфой. |
|---|
| 893 |
FilesNum := FilesNum+1; |
|---|
| 894 |
|
|---|
| 895 |
//И если нужно - вызвать функцию рекурсивно. |
|---|
| 896 |
if Recursive = true then begin |
|---|
| 897 |
Result := ReallyAddDirectory(AddLastSlash(DirName)+SearchRec.Name, Recursive); |
|---|
| 898 |
if Result = false then begin |
|---|
| 899 |
//Был какой-то ошибк. Брякаем. |
|---|
| 900 |
Break; |
|---|
| 901 |
end; |
|---|
| 902 |
end; |
|---|
| 903 |
end; |
|---|
| 904 |
end; |
|---|
| 905 |
|
|---|
| 906 |
until FindNext(SearchRec) <> 0; |
|---|
| 907 |
|
|---|
| 908 |
//Закрыть поиск. |
|---|
| 909 |
SysUtils.FindClose(SearchRec); |
|---|
| 910 |
end; |
|---|
| 911 |
end; |
|---|
| 912 |
|
|---|
| 913 |
begin |
|---|
| 914 |
//Функция может работать "рекурсивно". На самом деле прямой рекурсии этой функции даже в этом случае |
|---|
| 915 |
//не будет - рекурситься будут только "вложенные" функции. В любом случае - сначала подсчитывает |
|---|
| 916 |
//количество добавляемых файлов (либо рекурсивно либо нет, смотря что требуется), потом выделяется память |
|---|
| 917 |
//под массив, потом вызывается функция добавления данной папки, которая уже может быть рекурсивной если |
|---|
| 918 |
//это необходимо. Таким образом размер динамического массива определяется однократно, что позволяет не |
|---|
| 919 |
//заниматься копированием памяти каждый раз когда надо увеличить массив. Рекурсивная функция уже точно знает |
|---|
| 920 |
//сколько файлов будет добавлено и размер массива не трогает - только читает и добавляет инфу. |
|---|
| 921 |
|
|---|
| 922 |
//Инициализация. |
|---|
| 923 |
Result := false; |
|---|
| 924 |
|
|---|
| 925 |
//Получаем абсолютный путь.... |
|---|
| 926 |
if IsLocalPath(DirName) = true then begin |
|---|
| 927 |
//Если надо генерить - генерим. |
|---|
| 928 |
GlobalName := DelLastSlash(ResolveLocalPath(DirName,Self.GetGlobalRoot())); |
|---|
| 929 |
end |
|---|
| 930 |
else begin |
|---|
| 931 |
//Он уже глобальный. |
|---|
| 932 |
GlobalName := DelLastSlash(DirName); |
|---|
| 933 |
end; |
|---|
| 934 |
|
|---|
| 935 |
//Если нужно - получаем относительный путь. |
|---|
| 936 |
if Self.PathsAreAbsolute = false then begin |
|---|
| 937 |
LocalName := GetLocalPath(Self.GetGlobalRoot(),GlobalName); |
|---|
| 938 |
end; |
|---|
| 939 |
|
|---|
| 940 |
//Итак, во-первых подсчитать количество добавляемых файлов... |
|---|
| 941 |
AddingFiles := GetFilesNumber(GlobalName,Recursive)+1; //+1 - данная конкретная дира которая DirName |
|---|
| 942 |
//Теперь выставить правильный размер массива... FilesNum не трогаем - это в принципе счетчик тут. |
|---|
| 943 |
SetLength(FileList,FilesNum+AddingFiles); |
|---|
| 944 |
|
|---|
| 945 |
//Добавить текущую диру. |
|---|
| 946 |
//FilePath |
|---|
| 947 |
if Self.PathsAreAbsolute = true then begin |
|---|
| 948 |
//Имя должно быть абсолютное. |
|---|
| 949 |
FileList[FilesNum].FilePath := GlobalName; |
|---|
| 950 |
end |
|---|
| 951 |
else begin |
|---|
| 952 |
//Имя должно быть относительное |
|---|
| 953 |
FileList[FilesNum].FilePath := LocalName; |
|---|
| 954 |
end; |
|---|
| 955 |
//FileType |
|---|
| 956 |
FileList[FilesNum].FileType := Flist_Filetype_Directory; |
|---|
| 957 |
//+1 количество файлов в инфе. |
|---|
| 958 |
FilesNum := FilesNum+1; |
|---|
| 959 |
|
|---|
| 960 |
//Ок. Можно звать функцию для непосредственного чтения инфы директории, если надо то она и будет рекурситься. |
|---|
| 961 |
Result := ReallyAddDirectory(GlobalName, Recursive); |
|---|
| 962 |
|
|---|
| 963 |
end; |
|---|
| 964 |
|
|---|
| 965 |
function TFlistFormat.RemoveFile(const FileName : AnsiString) : boolean; |
|---|
| 966 |
//Удалить файл из базы. |
|---|
| 967 |
var |
|---|
| 968 |
RealSearchPath, TempStr : AnsiString; |
|---|
| 969 |
Finded : boolean; |
|---|
| 970 |
I, J : Integer; |
|---|
| 971 |
NewFileList : array of RFlistFile; |
|---|
| 972 |
DeletingElem, DummyElem : RFlistFile; |
|---|
| 973 |
|
|---|
| 974 |
begin |
|---|
| 975 |
//Инициализация |
|---|
| 976 |
Result := false; |
|---|
| 977 |
|
|---|
| 978 |
//Смотрим что там за путь в аргументе и если надо приводим его к тому виду как они в массиве. |
|---|
| 979 |
if Self.PathsAreAbsolute = true then begin |
|---|
| 980 |
//Если нужны абсолютные пути. |
|---|
| 981 |
if IsLocalPath(FileName) = true then begin |
|---|
| 982 |
//Если надо генерить - генерим. |
|---|
| 983 |
RealSearchPath := ResolveLocalPath(FileName,Self.GetGlobalRoot()); |
|---|
| 984 |
end |
|---|
| 985 |
else begin |
|---|
| 986 |
//Он уже глобальный. |
|---|
| 987 |
RealSearchPath := FileName; |
|---|
| 988 |
end; |
|---|
| 989 |
end |
|---|
| 990 |
else begin |
|---|
| 991 |
//Если нужны относительные пути. |
|---|
| 992 |
if IsLocalPath(FileName) = true then begin |
|---|
| 993 |
//Он уже локальный. |
|---|
| 994 |
RealSearchPath := FileName; |
|---|
| 995 |
end |
|---|
| 996 |
else begin |
|---|
| 997 |
//Генерим локальный |
|---|
| 998 |
RealSearchPath := GetLocalPath(Self.GetGlobalRoot(),FileName); |
|---|
| 999 |
end; |
|---|
| 1000 |
end; |
|---|
| 1001 |
|
|---|
| 1002 |
//Ищем файл с таким локальным\глобальным именем и удаляем его из массива. |
|---|
| 1003 |
Finded := false; |
|---|
| 1004 |
I := -1; |
|---|
| 1005 |
repeat |
|---|
| 1006 |
I := I+1; |
|---|
| 1007 |
if UpperCase(Self.FileList[I].FilePath) = UpperCase(RealSearchPath) then begin |
|---|
| 1008 |
//Нашли. |
|---|
| 1009 |
Finded := true; |
|---|
| 1010 |
end; |
|---|
| 1011 |
until (Finded = true) or (I = FilesNum-1); |
|---|
| 1012 |
|
|---|
| 1013 |
if Finded = true then begin |
|---|
| 1014 |
//Если нашли чего удалять, а удаляемый элемент не последний - двигаем элементы внутрях массива. |
|---|
| 1015 |
if I <> (FilesNum-1) then begin |
|---|
| 1016 |
Move(Self.FileList[I],DeletingElem,SizeOf(RFlistFile)); //Временно копируем инфу удаляемого элемента. |
|---|
| 1017 |
Move(Self.FileList[I+1],Self.FileList[I],SizeOf(RFlistFile)*(FilesNum-(I+1))); //Переносим инфу других элементов. |
|---|
| 1018 |
Move(DeletingElem,Self.FileList[FilesNum-1],SizeOf(RFlistFile)); //Копируем удаляемый элемент в конец массива чтоб его прочистило при смене размера массива (во избежание утечков памяти). |
|---|
| 1019 |
Move(DummyElem,DeletingElem,SizeOf(RFlistFile)); //Копируем во временный элемент инфу элемента заглушки - чтобы тупой сборщег мусора не полез по ссылкам и не заховал последний элемент массива раньше или позже (т.е. еще раз на пустое место) правильного времени. |
|---|
| 1020 |
end; |
|---|
| 1021 |
//Прочистить удаляемый элемент массива. |
|---|
| 1022 |
Self.FileList[FilesNum-1].CRC32 := 0; |
|---|
| 1023 |
Self.FileList[FilesNum-1].FilePath := ''; |
|---|
| 1024 |
Self.FileList[FilesNum-1].FileSize := 0; |
|---|
| 1025 |
Self.FileList[FilesNum-1].FileType := 0; |
|---|
| 1026 |
//И почистить массив. |
|---|
| 1027 |
FilesNum := FilesNum-1; |
|---|
| 1028 |
SetLength(Self.FileList,FilesNum); |
|---|
| 1029 |
//Done. |
|---|
| 1030 |
Result := true; |
|---|
| 1031 |
end; |
|---|
| 1032 |
end; |
|---|
| 1033 |
|
|---|
| 1034 |
function TFlistFormat.RemoveDirectory(const DirName : AnsiString) : boolean; |
|---|
| 1035 |
//Удалить диру (со всеми входящими файлами и дирами). |
|---|
| 1036 |
var |
|---|
| 1037 |
I : Integer; |
|---|
| 1038 |
RealSearchPath : AnsiString; |
|---|
| 1039 |
|
|---|
| 1040 |
begin |
|---|
| 1041 |
//Принцип действия следующий: двигаемся по массиву, если обнаруживаем child-а (в т.ч. и сама эта дира |
|---|
| 1042 |
//попадет в этот фильтр - явно её удалять и не надо) - то удаляем вышенаписанной функцией, счетчик |
|---|
| 1043 |
//отщелкиваем назад и идем дальше. |
|---|
| 1044 |
|
|---|
| 1045 |
//Инициализация. |
|---|
| 1046 |
Result := false; |
|---|
| 1047 |
|
|---|
| 1048 |
//Смотрим что там за путь в аргументе и если надо приводим его к тому виду как они в массиве. |
|---|
| 1049 |
if Self.PathsAreAbsolute = true then begin |
|---|
| 1050 |
//Если нужны абсолютные пути. |
|---|
| 1051 |
if IsLocalPath(DirName) = true then begin |
|---|
| 1052 |
//Если надо генерить - генерим. |
|---|
| 1053 |
RealSearchPath := ResolveLocalPath(DirName,Self.GetGlobalRoot()); |
|---|
| 1054 |
end |
|---|
| 1055 |
else begin |
|---|
| 1056 |
//Он уже глобальный. |
|---|
| 1057 |
RealSearchPath := DirName; |
|---|