root/trunk/IssFormat.pas

Revision 158, 51.2 kB (checked in by sagrer, 5 months ago)
  1. Поправлены параметры запуска VerRevUpdater? через IDE
  2. Прикручена локализация в FlistFormat?.pas, IssFormat?.pas, SconfFormat.pas, PascalCodeModifier?.pas
  3. Прикручена локализация к IssBuilder?.
  4. Добавлен перевод на русский для IssBuilder?
  5. Выполнен #34
  • Property svnmailer:content-charset set to cp1251
<
Line 
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 //       Модуль для работы с файлами *.iss        //
19 //       Это скрипты для сборки инсталляций       //
20 //         с помощью InnoSetup compiler           //
21 ////////////////////////////////////////////////////
22
23 unit IssFormat;
24
25 {$mode objfpc}{$H+}
26
27 interface
28
29 uses
30   Classes, SysUtils, LCLAnIniFile, ExtraFunctionsLcl, FlistFormat,
31   PascalCodeModifier, ExtraFileUtilsLcl, TranslManager;
32  
33 const
34   //Типо константы-настройки... в теории когда нить можно вынести это дело в какой нить конфег если очень понадобится.
35   IssF_CurrMainComponentName = 'CurrVersion_Main';    //Имя компонента с "текущей" полной версией.
36   IssF_AlwaysInstallComponentName = 'AlwaysInstall';  //Имя компонента для обязательной установки.
37   IssF_FilesAddFlags = true;        //Добавлять ли флаги на добавляемые файлы.
38   IssF_DirsAddFlags = false;        //Добавлять ли флаги на добавляемые директории.
39   IssF_FilesAddingFlags = 'overwritereadonly replacesameversion sortfilesbyextension';    //Собсно флаги, добавляемые для добавляемых файлов.
40   IssF_DirsAddingFlags = '';                                         //Собсно флаги, добавляемые для добавляемых директорий.
41   //Строки для дополнения [Code] при парсинге.
42   IssF_PreCode = 'Program InnoScript;'+#13+#10;     //То что до кода.
43   IssF_PostCode = #13+#10+'begin end.';             //То что после кода.
44  
45 type
46   TIssFormat = class (TAnIniFile)              //Класс для работы со скриптами (*.iss) для Inno Setup Compiler. В принципе просто как набор дополнительных методов...
47   private
48     PasModifier : TPascalCodeModifier;
49     PasModifIsActual : Boolean;
50     //Закрытые методы.
51     function ElementListHas(const ElementList, CheckableComponent : AnsiString) : Boolean;   //Проверить - содержится ли имя элемента в списке.
52     function UpdatePasModifier() : Boolean;           //Заполнить PasModifier инфой из секции [Code].
53     function SaveFromPasModifier() : Boolean;         //Вернуть инфу из PasModifier обратно в [Code].
54   public
55     //Переменные.
56     ErrorMessage : AnsiString;
57    
58     //Конструкторы-деструкторы...
59     Constructor Create; override;
60     Destructor Destroy; override;
61    
62     //Открытые методы.
63     procedure MakNewFile(); override;   //Очищает инфу класса.
64     Procedure RemoveSection(const SectName : string); override;   //Полностью удалить секцию.
65     Procedure WriteRawSection(const SectName, SectContent : string); override; //Перезаписать всё содержимое секции из строки.
66     procedure ClearFiles();             //Удалить секции про файлы - в т.ч. про удаляемые файлы.
67     procedure ClearIcons();             //Удалить секцию про иконки.
68     procedure ClearRegistry();          //Удалить секцию про реестр.
69     function UpdateInfoToVerUpdate(const OldVerIssFile, OldVerCompName : AnsiString) : Boolean;   //Добавить инфу по изменению иконок и реестра для обновления с более старой версии.
70     function AddFilesFromFlist(var FlistFile : TFlistFormat ; const ComponentName : AnsiString) : Boolean;        //Добавить устанавливаемые файлы из Flist-а для указанного компонента.
71     function AddFilesFromFlist(const FlistFileName, ComponentName : AnsiString) : Boolean;        //Добавить устанавливаемые файлы из Flist-а для указанного компонента.
72     function AddFilesFromDir(const DirName, ComponentName : AnsiString) : Boolean;   //Добавить устанавливаемые файлы из Flist-a для указанного компонента.
73     function AddNewFilesFromFlists(var OldFlistFile, NewFlistFile : TFlistFormat; const ComponentName : AnsiString) : Boolean;   //Добавить устанавливаемые файлы из сравнения старого и нового FList-а для указанного компонента.
74     function AddNewFilesFromFlists(const OldFlistFileName, NewFlistFileName, ComponentName : AnsiString) : Boolean;     //Добавить устанавливаемые файлы из сравнения старого и нового FList-а для указанного компонента.
75     function AddNewFilesFromDirs(const OldDirName, NewDirName, ComponentName : AnsiString) : Boolean;    //Добавить устанавливаемые файлы из сравнения старой и новой диры для указанного компонента.
76     function ReadCodeConstValue(const ConstName : AnsiString) : AnsiString;  //Прочитать значение конкретной константы.
77     function WriteCodeConstValue(const ConstName, ConstValue : AnsiString) : Boolean;    //Записать значение конкретной константы.
78     function CodeFunctionExists(const FunctionName : AnsiString) : Boolean;   //Существует ли такая функция в коде?
79     function WriteCodeFunction(const FunctionName, FunctionContent : AnsiString) : Boolean;   //Записать функцию в Code, если уже есть - заменить.
80     function InstallTypeExists(const InstallTypeName : AnsiString) : Boolean;   //Существует ли тип инсталляции?
81     function RemoveInstalType(const InstallTypeName : AnsiString) : Boolean;   //Удалить тип инсталляхи. false вернет если типа с таким именем не было, иначе всегда true.
82     procedure WriteInstallType(const InstallTypeName, FullInstTypeString : AnsiString);    //Вписать тип инсталляции, если нужно - заменить имеющийся с тем же именем. FullInstTypeString - полная строчка для секции [Types].
83     function ComponentExists(const ComponentName : AnsiString) : Boolean;    //Существует ли такой компонент?
84     function RemoveComponent(const ComponentName : AnsiString) : Boolean;    //Удалить компонент. false вернет если такого компонента и не было, во всех остальных случаях возвращает true.
85     procedure WriteComponent(const ComponentName, FullComponentString : AnsiString);   //Вписать компонент, если нужно - заменить существующий с таким же именем. FullComponentString - полная строчка для секции [Components].
86     //Открытые методы для чтения\записи каких-либо значений стандартных секций.
87     function GetSourceDir() : AnsiString;          //Прочитать SourceDir.
88     function GetOutputDir() : AnsiString;          //Прочитать OutputDir.
89     procedure SetSourceDir(const SourceDir : AnsiString);     //Записать SourceDir.
90     procedure SetOutputDir(const OutputDir : AnsiString);     //Записать OutputDir.
91   end;
92
93 implementation
94
95 /////////////////////////////////////////////
96 //              TIssFormat                 //
97 /////////////////////////////////////////////
98
99 //-----------------------------------------//
100 //        Конструкторы-деструкторы...      //
101 //-----------------------------------------//
102
103 Constructor TIssFormat.Create;
104 begin
105   //Конструктор. Во избежание глюков.
106   inherited;
107  
108   //Инициализировать вложенные объекты.
109   Self.PasModifier := TPascalCodeModifier.Create;
110  
111   //Вызов начальной очистки.
112   Self.MakNewFile();
113 end;
114
115 Destructor TIssFormat.Destroy;
116 begin
117   //Типа деструктор.
118   Self.MakNewFile();
119   inherited;
120 end;
121
122 //------------------------------------------//
123 //           Закрытые методы...             //
124 //------------------------------------------//
125
126 function TIssFormat.ElementListHas(const ElementList, CheckableComponent : AnsiString) : Boolean;
127 //Проверить - содержится ли имя элемента в списке.
128 var
129   TempList, TempValue, TempCheck : AnsiString;
130 begin
131   //Инициализация.
132   Result := false;
133   TempCheck := LowerCase(CheckableComponent);
134   TempList := Trim(ElementList);
135  
136   //Проверка...
137   repeat
138     if TempList <> '' then begin
139       TempValue := LowerCase(Parse(TempList,' '));
140       TempList := Trim(TempList);
141       if TempValue = TempCheck then begin
142         //Нашли.
143         Result := true;
144         TempList := '';
145       end;
146     end;
147   until TempList = '';
148  
149 end;
150
151 function TIssFormat.UpdatePasModifier() : Boolean;
152 //Заполнить PasModifier инфой из секции [Code].
153 begin
154   //Инициализация.
155   Result := true;
156  
157   //Собсно апдейтим.
158   if Self.PasModifIsActual = false then begin
159     //Если есть такая необходимость.
160     if Self.SectionExists('Code') = true then begin
161       //Есть такая секция. Читаем.
162       Self.PasModifier.MakNewFile;
163       Self.PasModifier.FileString := IssF_PreCode+Self.ReadRawSection('Code')+IssF_PostCode;
164       try
165         if Self.PasModifier.ReParseFile() = false then begin
166           //Сюда попадет если была обработанная уже ошибка в ReParseFile.
167           Self.ErrorMessage := _('TPascalCodeModifier, while parsing error: ')+Self.PasModifier.ErrorMessage;
168           Result := false;
169           Exit;
170         end;
171       except
172         //Если была ошибка парсинга
173         on E: Exception do begin
174           Self.ErrorMessage := _('TPascalCodeModifier, while parsing error: ')+E.Message;
175           Result := false;
176           Exit;
177         end;
178       end;
179      
180       //Прочитали.
181       Self.PasModifIsActual := true;
182     end;
183   end;
184 end;
185
186 function TIssFormat.SaveFromPasModifier() : Boolean;
187 //Вернуть инфу из PasModifier обратно в [Code].
188 begin
189   //Инициализация.
190   Result := true;
191  
192   if Self.PasModifIsActual = true then begin
193     //Ога, есть чего забросить. Забрасываем.
194     Self.WriteRawSection('Code', Copy(Self.PasModifier.FileString, Length(IssF_PreCode)+1, Length(Self.PasModifier.FileString)-(Length(IssF_PreCode)+Length(IssF_PostCode))) );
195     Self.PasModifIsActual := true;
196   end;
197 end;
198
199 //------------------------------------------//
200 //            Открытые методы...            //
201 //------------------------------------------//
202
203 procedure TIssFormat.MakNewFile();
204 //Очищает инфу класса.
205 begin
206   inherited;
207   Self.PasModifier.MakNewFile;
208   Self.PasModifIsActual := false;
209   ErrorMessage := '';
210 end;
211
212 Procedure TIssFormat.RemoveSection(const SectName : string);
213 //Полностью удалить секцию.
214 begin
215   //Смысл оверрайдинга - чтобы отслеживать изменения секции [Code].
216   //Сначала оригинальная функция, без изменений...
217   inherited;
218  
219   //И если это [Code] то сделать отметку.
220   if (LowerCase(SectName) = 'code') and (Self.PasModifIsActual = true) then begin
221     Self.PasModifIsActual := false;
222   end;
223 end;
224
225 Procedure TIssFormat.WriteRawSection(const SectName, SectContent : string);
226 //Перезаписать всё содержимое секции из строки.
227 begin
228   //Смысл оверрайдинга - чтобы отслеживать изменения секции [Code].
229   //Сначала оригинальная функция, без изменений...
230   inherited;
231  
232   //И если это [Code] то сделать отметку.
233   if (LowerCase(SectName) = 'code') and (Self.PasModifIsActual = true) then begin
234     Self.PasModifIsActual := false;
235   end;
236 end;
237
238 procedure TIssFormat.ClearFiles();
239 //Удалить секции про файлы - в т.ч. про удаляемые файлы.
240 begin
241   //Итак - под действие этой функции попадают секции [Dirs], [Files], [InstallDelete]. Чистим их.
242   Self.WriteRawSection('Dirs','');
243   Self.WriteRawSection('Files','');
244   Self.WriteRawSection('InstallDelete','');
245 end;
246
247 procedure TIssFormat.ClearIcons();
248 //Удалить секцию про иконки.
249 begin
250   //Под действие данной функции попадает секция [Icons].
251   Self.WriteRawSection('Icons','');
252 end;
253
254 procedure TIssFormat.ClearRegistry();
255 //Удалить секцию про реестр.
256 begin
257   //Под действие данной функции попадает секция [Registry].
258   Self.WriteRawSection('Registry','');
259 end;
260
261 function TIssFormat.UpdateInfoToVerUpdate(const OldVerIssFile, OldVerCompName : AnsiString) : Boolean;
262 //Добавить инфу по изменению иконок и реестра для обновления с более старой версии.
263 var
264   OldIconList, NewIconList, DeleteList, OldRegistryList, NewRegistryList : AIniValueList;
265   OldIssFile : TIssFormat;
266   I, oI : Integer;
267   NewCheckableElem, ElemIsAddable : Boolean;
268  
269 begin
270   //Инициализация...
271   Result := false;
272   OldIssFile := TIssFormat.Create;
273   SetLength(OldIconList,0,0);
274   SetLength(NewIconList,0,0);
275   SetLength(DeleteList,0,0);
276   SetLength(OldRegistryList,0,0);
277   SetLength(NewRegistryList,0,0);
278  
279   //Пытаемся прочитать "старый" файлег...
280   if OldIssFile.Load(OldVerIssFile) = true then begin
281     //Для начала прочитаем иконки с текущего файла...
282     Self.ReadIniValueList('Icons',NewIconList);
283     //Ок. Теперь читаем иконки из "старого" файла...
284     OldIssFile.ReadIniValueList('Icons',OldIconList);
285     //Ок. Теперь прочитаем команды на удаление с текущего файла...
286     Self.ReadIniValueList('InstallDelete',DeleteList);
287     //Читаем инфу про реестр с текущего файла...
288     Self.ReadIniValueList('Registry',NewRegistryList);
289     //Читаем инфу про реестр из "старого" файла.
290     OldIssFile.ReadIniValueList('Registry',OldRegistryList);
291    
292     //Обрабатываем иконки:
293     if (Length(OldIconList) > 0) and (Length(NewIconList) > 0) then begin
294       //Если там есть хоть одна иконка - сканим...
295
296       //Для начала - добавим в новый файл те иконки которых нет в старом...
297       //Считается что иконки текущей версии (и в старой и в новой) - те что с компонентом "CurrVersion_Main" - ищем такие какие есть в новом файле и нет в старом.
298       for I := 0 to Length(NewIconList)-1 do begin
299         //Индикатор - добавлять ли иконку в конце интерации цикла.
300         ElemIsAddable := false;
301         //Проверяем - относится ли иконка к "текущему" компоненту.
302         NewCheckableElem := ElementListHas(GetIniValueListValue(NewIconList,I,'Components'),IssF_CurrMainComponentName);
303
304         //Если иконка относится к нужному компоненту - то ищем - есть ли такая же и в старом списке, если нет то её надо добавить.
305         if NewCheckableElem = true then begin
306           //Устанавливаем идикатор...
307           ElemIsAddable := true;   //По умолчанию считаем что иконку эту нужно добавить в компонент, проверка ниже может это отменить.
308           //Собсно проверяем второй список.
309           for oI := 0 to Length(OldIconList)-1 do begin
310             //Все предельно просто. Запись о иконке должна быть идентична тому что в новом списке, вот и все. Если идентичной не обнаружено то подлежит добавлению.
311             //Допустимо различие только регистра в имени самого файла.
312             if Self.CompareIniValueElements(NewIconList,OldIconList, I, oI, true, 'Filename') = true then begin
313               if Self.CompareIniValueElements(NewIconList,OldIconList, I, oI, false, 'all, Filename') = true then begin
314                 //Идентичны - иконка добавлению в компонент не подлежит.
315                 ElemIsAddable := false;
316               end;
317             end;
318           end;
319         end;
320        
321         //Если в итоге решили, что иконку надо добавить - добавляем.
322         if ElemIsAddable = true then begin
323           //Увеличиваем размер массива...
324           SetLength(NewIconList,Length(NewIconList)+1);
325           //Копируем элемент...
326           Self.CopyIniValueListElement(NewIconList,NewIconList,I,Length(NewIconList)-1);
327           //Меняем компонент иконке...
328           Self.ChangeIniValueListValue(NewIconList,Length(NewIconList)-1,'Components',OldVerCompName);
329         end;
330       end;
331      
332       //Ок, добавили. Теперь добавим в новый файл команды на удаление тех иконок, которые были в старом файле, но исчезли в новом.
333       for I := 0 to Length(OldIconList)-1 do begin
334         //Индикатор - добавлять ли иконку (команду на её удаление) в конце интерации цикла.
335         ElemIsAddable := false;
336         //Проверяем - относится ли иконка к "текущему" компоненту, либо к AlwaysInstall, которые тоже надо удалять от старых версий.
337         NewCheckableElem := (ElementListHas(GetIniValueListValue(OldIconList,I,'Components'),IssF_CurrMainComponentName)) or (ElementListHas(GetIniValueListValue(OldIconList,I,'Components'),IssF_AlwaysInstallComponentName));
338
339         //Если иконка относится к нужному компоненту - то ищем - есть ли такая же и в новом списке, если нету - добавляем команду на удаление.
340         if NewCheckableElem = true then begin
341           //Устанавливаем идикатор...
342           ElemIsAddable := true;   //По умолчанию считаем что иконку эту нужно удалять при инсталляции...
343           //Собсно проверяем "новый" список.
344           for oI := 0 to Length(NewIconList)-1 do begin
345             //Все предельно просто. Запись о иконке должна быть идентична тому что в новом списке, вот и все. Если идентичной не обнаружено то подлежит удалению.
346             //Допустимо различие только регистра в имени самого файла.
347             if Self.CompareIniValueElements(OldIconList,NewIconList, I, oI, true, 'Filename') = true then begin
348               if Self.CompareIniValueElements(OldIconList,NewIconList, I, oI, false, 'all, Filename') = true then begin
349                 //Идентичны - иконка удалению не подлежит.
350                 ElemIsAddable := false;
351               end;
352             end;
353           end;
354         end;
355
356         //Если в итоге решили, что надо добавить команду на удаление иконки - добавляем.
357         if ElemIsAddable = true then begin
358           //Увеличиваем размер массива...
359           SetLength(DeleteList,Length(DeleteList)+1);
360           //Добавляем в новый элемент 3 нужных значений команды:
361           SetLength(DeleteList[Length(DeleteList)-1],3);
362           DeleteList[Length(DeleteList)-1,0].Name := 'Name';
363           DeleteList[Length(DeleteList)-1,0].Value := GetIniValueListValue(OldIconList,I,'Name');
364           DeleteList[Length(DeleteList)-1,1].Name := 'Type';
365           DeleteList[Length(DeleteList)-1,1].Value := 'files';
366           DeleteList[Length(DeleteList)-1,2].Name := 'Components';
367           DeleteList[Length(DeleteList)-1,2].Value := OldVerCompName;
368         end;
369
370       end;
371      
372       //Ок, команды добавлены в списки в памяти. Вполне возможно что списки (NewIconList и DeleteList) изменились - сохраняем их обратно в файл.
373       Self.WriteIniValueList('Icons',NewIconList);
374       Self.WriteIniValueList('InstallDelete',DeleteList);
375     end;
376    
377     //Иконки обработаны. Обрабатываем реестр, по почти аналогичному принципу...
378     if (Length(OldRegistryList) > 0) and (Length(NewRegistryList) > 0) then begin
379       //Для начала - добавим в новый файл те записи реестре, которых нет в старом...
380       for I := 0 to Length(NewRegistryList)-1 do begin
381         //Индикатор - добавлять ли запись в конце интерации цикла.
382         ElemIsAddable := false;
383         //Проверяем - относится ли запись к "текущему" компоненту.
384         NewCheckableElem := ElementListHas(GetIniValueListValue(NewRegistryList,I,'Components'),IssF_CurrMainComponentName);
385
386         //Если запись относится к нужному компоненту - то ищем - есть ли такая же и в старом списке, если нет то её надо добавить.
387         if NewCheckableElem = true then begin
388           //Устанавливаем идикатор...
389           ElemIsAddable := true;   //По умолчанию считаем что запись эту нужно добавить в компонент, проверка ниже может это отменить.
390           //Собсно проверяем второй список.
391           for oI := 0 to Length(OldRegistryList)-1 do begin
392             //Все предельно просто. Запись о записи %) должна быть идентична тому что в новом списке, вот и все. Если идентичной не обнаружено то подлежит добавлению.
393             if Self.CompareIniValueElements(NewRegistryList,OldRegistryList, I, oI, true, '') = true then begin
394               //Идентичны - запись добавлению в компонент не подлежит.
395               ElemIsAddable := false;
396             end;
397           end;
398         end;
399
400         //Если в итоге решили, что запись надо добавить - добавляем.
401         if ElemIsAddable = true then begin
402           //Увеличиваем размер массива...
403           SetLength(NewRegistryList,Length(NewRegistryList)+1);
404           //Копируем элемент...
405           Self.CopyIniValueListElement(NewRegistryList,NewRegistryList,I,Length(NewRegistryList)-1);
406           //Меняем компонент иконке...
407           Self.ChangeIniValueListValue(NewRegistryList,Length(NewRegistryList)-1,'Components',OldVerCompName);
408         end;
409       end;
410      
411       //Ок, добавили. Теперь добавим в новый файл команды на удаление тех записей, которые были в старом файле, но исчезли в новом, являются либо создавабельными ключами, либо создавабельными (не none) значениями.
412       for I := 0 to Length(OldRegistryList)-1 do begin
413         //Индикатор - добавлять ли команду на удаление в конце интерации цикла.
414         ElemIsAddable := false;
415         //Проверяем - относится ли запись к "текущему" компоненту, либо к AlwaysInstall, которые тоже надо удалять от старых версий.
416         NewCheckableElem := (ElementListHas(GetIniValueListValue(OldRegistryList,I,'Components'),IssF_CurrMainComponentName)) or (ElementListHas(GetIniValueListValue(OldRegistryList,I,'Components'),IssF_AlwaysInstallComponentName));
417
418         //Если запись относится к нужному компоненту - то ищем - есть ли такая же и в новом списке, если нету - добавляем команду на удаление (разную, смотря что за запись, может быть и не нужно удалять, а если и нужно то можно по разному).
419         if NewCheckableElem = true then begin
420           //Устанавливаем идикатор...
421           ElemIsAddable := true;   //По умолчанию считаем что иконку эту нужно удалять при инсталляции...
422           //Собсно проверяем "новый" список.
423           for oI := 0 to Length(NewRegistryList)-1 do begin
424             //Все предельно просто. Запись должна быть идентична тому что в новом списке, вот и все. Если идентичной не обнаружено то подлежит удалению.
425             if Self.CompareIniValueElements(OldRegistryList,NewRegistryList, I, oI, true, '') = true then begin
426               //Идентичны - запись удалению не подлежит.
427               ElemIsAddable := false;
428             end;
429           end;
430         end;
431
432         //Если в итоге решили, что надо добавить команду на удаление иконки - добавляем.
433         if ElemIsAddable = true then begin
434           //В зависимости от того что из себя запись представляет - и таки надо ли её все-же удалять % ))).
435           //Ключ ли это?
436           if Self.IniValueListValueExists(OldRegistryList,I,'ValueType') = false then begin
437             //Да, это ключ. А не команда ли это на удаление?
438             if ElementListHas(GetIniValueListValue(OldRegistryList,I,'Flags'),'deletekey') = false then begin
439               //Не, нифига. Обычная создавалка ключа. Тогда собсно и добавляем команду-удалялку:
440               //Увеличиваем размер массива...
441               SetLength(NewRegistryList,Length(NewRegistryList)+1);
442               //Добавляем в новый элемент 4 нужных значений команды:
443               SetLength(NewRegistryList[Length(NewRegistryList)-1],4);
444               NewRegistryList[Length(NewRegistryList)-1,0].Name := 'Root';
445               NewRegistryList[Length(NewRegistryList)-1,0].Value := GetIniValueListValue(OldRegistryList,I,'Root');
446               NewRegistryList[Length(NewRegistryList)-1,1].Name := 'Subkey';
447               NewRegistryList[Length(NewRegistryList)-1,1].Value := GetIniValueListValue(OldRegistryList,I,'Subkey');
448               NewRegistryList[Length(NewRegistryList)-1,2].Name := 'Flags';
449               NewRegistryList[Length(NewRegistryList)-1,2].Value := 'deletekey';
450               NewRegistryList[Length(NewRegistryList)-1,3].Name := 'Components';
451               NewRegistryList[Length(NewRegistryList)-1,3].Value := OldVerCompName;
452             end
453             else begin
454               //Ага, удалялка, тогда она нам нафег не сдалась, фтопку её, ничО не делать и все.
455             end;
456           end
457           else begin
458             //Нет, это значение. А не none ли оно случаем?
459             if LowerCase(GetIniValueListValue(OldRegistryList,I,'ValueType')) <> 'none' then begin
460               //Не, оно не none - проверяем, нету ли там случаем команды на удаление значения?
461               if ElementListHas(GetIniValueListValue(OldRegistryList,I,'Flags'),'deletevalue') = false then begin
462                 //Ага, надо добавить удалялку значения - собсно и добавляем:
463                 //Увеличиваем размер массива...
464                 SetLength(NewRegistryList,Length(NewRegistryList)+1);
465                 //Добавляем в новый элемент 6 нужных значений команды:
466                 SetLength(NewRegistryList[Length(NewRegistryList)-1],6);
467                 NewRegistryList[Length(NewRegistryList)-1,0].Name := 'Root';
468                 NewRegistryList[Length(NewRegistryList)-1,0].Value := GetIniValueListValue(OldRegistryList,I,'Root');
469                 NewRegistryList[Length(NewRegistryList)-1,1].Name := 'Subkey';
470                 NewRegistryList[Length(NewRegistryList)-1,1].Value := GetIniValueListValue(OldRegistryList,I,'Subkey');
471                 NewRegistryList[Length(NewRegistryList)-1,2].Name := 'ValueType';
472                 NewRegistryList[Length(NewRegistryList)-1,2].Value := 'none';
473                 NewRegistryList[Length(NewRegistryList)-1,3].Name := 'ValueName';
474                 NewRegistryList[Length(NewRegistryList)-1,3].Value := GetIniValueListValue(OldRegistryList,I,'ValueName');
475                 NewRegistryList[Length(NewRegistryList)-1,4].Name := 'Flags';
476                 NewRegistryList[Length(NewRegistryList)-1,4].Value := 'deletevalue';
477                 NewRegistryList[Length(NewRegistryList)-1,5].Name := 'Components';
478                 NewRegistryList[Length(NewRegistryList)-1,5].Value := OldVerCompName;
479               end
480               else begin
481                 //Это удалялка значения - нам не неё пофик.
482               end;
483             end
484             else begin
485               //Если оно типа none то нифига делать не надо - пусть оно в некоторых случаях и может создать ключег, но поскольку
486               //это таки команда на создание значения (пусть и бессмысленная и значение не создастся), то мы не имеем права удалять
487               //ключ который может быть создается чем-то там еще и можнт содержать значения, которые эта команда нифига не создавала.
488             end;
489           end;
490         end;
491       end;
492      
493       //Ок, команды добавлены в список в памяти. Вполне возможно что этот список (NewRegistryList) изменился - сохраняем его обратно в файл.
494       Self.WriteIniValueList('Registry',NewRegistryList);
495     end;
496   end;
497  
498   //Готово.
499   Result := true;
500  
501   //Чистим мусор...
502   OldIssFile.Free;
503   SetLength(OldIconList,0,0);
504   SetLength(NewIconList,0,0);
505   SetLength(DeleteList,0,0);
506   SetLength(OldRegistryList,0,0);
507   SetLength(NewRegistryList,0,0);
508 end;
509
510 function TIssFormat.AddFilesFromFlist(var FlistFile : TFlistFormat ; const ComponentName : AnsiString) : Boolean;
511 //Добавить устанавливаемые файлы из Flist-а для указанного компонента.
512 var
513   DirsList, FilesList : AIniValueList;
514   RealDirsListSize, RealFilesListSize, I, ElemsNum : Integer;
515   TempStr : AnsiString;
516  
517 begin
518   //Инициализация...
519   Result := false;
520   SetLength(DirsList,0,0);
521   SetLength(FilesList,0,0);
522
523   //Прочитать списки директорий и файлов из текущего файла...
524   Self.ReadIniValueList('Dirs',DirsList);
525   Self.ReadIniValueList('Files',FilesList);
526   //Выставить ориентировочный размер для списков, исходя из количества элементов в flist.
527   RealDirsListSize := Length(DirsList);
528   RealFilesListSize := Length(FilesList);
529   SetLength(DirsList,RealDirsListSize+FlistFile.FilesNum);
530   SetLength(FilesList,RealFilesListSize+FlistFile.FilesNum);
531   //Ну, собсно погнали по списку flist-а.
532   for I := 0 to FlistFile.FilesNum-1 do begin
533     //Смотрим шё за субж - дира или файло?
534     if FlistFile.FileList[I].FileType = Flist_Filetype_File then begin
535       //Файл. Добавляем. Считаем количество элементов в строке файла.
536       ElemsNum := 3;  //Это минимум.
537       if IssF_FilesAddFlags = true then begin
538         //Добавлять флаги.
539         ElemsNum := ElemsNum+1;
540       end;
541       //Собсно выделяем память..
542       SetLength(FilesList[RealFilesListSize],ElemsNum);
543       //Пишем инфу для добавляемого файла...
544       TempStr := GetLocalPath(FlistFile.GetGlobalRoot(),FlistFile.GetRealElementName(I));
545       FilesList[RealFilesListSize,0].Name := 'Source';
546       FilesList[RealFilesListSize,0].Value := RightStr(TempStr,Length(TempStr)-2);
547       FilesList[RealFilesListSize,1].Name := 'DestDir';
548       FilesList[RealFilesListSize,1].Value := AddLastSlash('{app}'+ExtractFilePath(RightStr(TempStr,Length(TempStr)-1)));
549       FilesList[RealFilesListSize,2].Name := 'Components';
550       FilesList[RealFilesListSize,2].Value := ComponentName;
551       if IssF_FilesAddFlags = true then begin
552         FilesList[RealFilesListSize,3].Name := 'Flags';
553         FilesList[RealFilesListSize,3].Value := IssF_FilesAddingFlags;
554       end;
555       //Увеличиваем счетчик количества элементов в массиве.
556       RealFilesListSize := RealFilesListSize+1;
557     end
558     else if FlistFile.FileList[I].FileType = Flist_Filetype_Directory then begin
559       //Директория. Не ссылка ли это на себя?
560       TempStr := GetLocalPath(FlistFile.GetGlobalRoot(),FlistFile.GetRealElementName(I));
561       if Length(TempStr) > 2 then begin
562         //Да не, нормальная директория. Добавляем. Считаем количество элементов в строке файла.
563         ElemsNum := 2;  //Это минимум.
564         if IssF_DirsAddFlags = true then begin
565           //Добавлять флаги.
566           ElemsNum := ElemsNum+1;
567         end;
568         //Собсно выделяем память...
569         SetLength(DirsList[RealDirsListSize],ElemsNum);
570         //Пишем инфу для добавляемой директории...
571         DirsList[RealDirsListSize,0].Name := 'Name';
572         DirsList[RealDirsListSize,0].Value := DelLastSlash('{app}'+RightStr(TempStr,Length(TempStr)-1));
573         DirsList[RealDirsListSize,1].Name := 'Components';
574         DirsList[RealDirsListSize,1].Value := ComponentName;
575         if IssF_DirsAddFlags = true then begin
576           DirsList[RealDirsListSize,2].Name := 'Flags';
577           DirsList[RealDirsListSize,2].Value := IssF_DirsAddingFlags;
578         end;
579         //Увеличиваем счетчик количества элементов в массиве.
580         RealDirsListSize := RealDirsListSize+1;
581       end;
582     end;
583   end;
584  
585   //Все добавлено. Уменьшаем размеры списков до их реального размера...
586   SetLength(DirsList,RealDirsListSize);
587   SetLength(FilesList,RealFilesListSize);
588  
589   //Записываем полученные списки обратно в файл.
590   Self.WriteIniValueList('Dirs',DirsList);
591   Self.WriteIniValueList('Files',FilesList);
592  
593   //Возвращаем результат...
594   Result := true;
595
596   //Уборка мусора...
597   SetLength(DirsList,0,0);
598   SetLength(FilesList,0,0);
599 end;
600
601 function TIssFormat.AddFilesFromFlist(const FlistFileName, ComponentName : AnsiString) : Boolean;
602 //Добавить устанавливаемые файлы из Flist-а для указанного компонента.
603 var
604   FlistFile : TFlistFormat;
605 begin
606   //Инициализация...
607   Result := false;
608   FlistFile := TFlistFormat.Create;
609  
610   //Если flist-файлег есть - читаем его.
611   if FileExists(FlistFileName) = true then begin
612     //Прочитать файлег.
613     FlistFile.Load(FlistFileName);
614     //Проставить корень Flist-у.
615     FlistFile.GlobalRoot := Self.GetSourceDir();
616     //Вызвать функцию реально выполняющую задачу.
617     Result := Self.AddFilesFromFlist(FlistFile,ComponentName);
618   end;
619  
620   //Уборка мусора...
621   FlistFile.Free;
622 end;
623
624 function TIssFormat.AddFilesFromDir(const DirName, ComponentName : AnsiString) : Boolean;
625 //Добавить устанавливаемые файлы из Flist-a для указанного компонента.
626 var
627   FlistFile : TFlistFormat;
628 begin
629   //Инициализация...
630   Result := false;
631   FlistFile := TFlistFormat.Create;
632
633   //Настройка... в основном в целях оптимизации - нефиг читать инфу и делать преобразования например тех же путей которые никогда не понадобятся.
634   FlistFile.PathsAreAbsolute := true;
635   FlistFile.AddSize := false;
636   FlistFile.AddCRC32 := false;
637   FlistFile.GlobalRoot := Self.GetSourceDir();
638  
639   //Читаем инфу про директорию в объект flist-а.
640   if FlistFile.AddRealDirectory(DirName,true) = true then begin
641     //Если все прочитано успешно - вызвать функцию реально выполняющую задачу.
642     Result := Self.AddFilesFromFlist(FlistFile,ComponentName);
643   end;
644
645   //Уборка мусора...
646   FlistFile.Free;
647 end;
648
649 function TIssFormat.AddNewFilesFromFlists(var OldFlistFile, NewFlistFile : TFlistFormat; const ComponentName : AnsiString) : Boolean;
650 //Добавить устанавливаемые файлы из сравнения старого и нового FList-а для указанного компонента.
651 var
652   ComparedList : AComparedList;
653   DirsList, FilesList, DeleteList, DirDeleteList : AIniValueList;
654   RealDirsListSize, RealFilesListSize, RealDeleteListSize, RealDirDeleteListSize, I, ElemsNum : Integer;
655   //TestStr : AnsiString;
656  
657 begin
658   //Инициализация.
659   Result := false;
660   SetLength(ComparedList,0);
661   SetLength(DirsList,0,0);
662   SetLength(FilesList,0,0);
663   SetLength(DeleteList,0,0);
664   SetLength(DirDeleteList,0,0);
665  
666   //Прочитать списки из текущего файла...
667   Self.ReadIniValueList('Dirs',DirsList);
668   Self.ReadIniValueList('Files',FilesList);
669   Self.ReadIniValueList('InstallDelete',DeleteList);
670  
671   //Cравниваем файлы.
672   OldFlistFile.CompareWithFlist(NewFlistFile,'.\',ComparedList);
673   //И упрощаем список сравнения дабы не усложнять здешний код без нужды.
674   OldFlistFile.ConvertToSimpleComparedList(ComparedList);
675  
676   //Выставить ориентировочный размер для списков, исходя из количества элементов в ComparedList.
677   RealDirsListSize := Length(DirsList);
678   RealFilesListSize := Length(FilesList);
679   RealDeleteListSize := Length(DeleteList);
680   RealDirDeleteListSize := 0;
681   SetLength(DirsList,RealDirsListSize+Length(ComparedList));
682   SetLength(FilesList,RealFilesListSize+Length(ComparedList));
683   SetLength(DeleteList,RealDeleteListSize+Length(ComparedList));
684   SetLength(DirDeleteList,Length(ComparedList));
685  
686   //Теперь пробегаемся по массиву, добавляем команды на удаление файлов\директорий и на установку новых.
687   for I := 0 to Length(ComparedList)-1 do begin
688     //TestStr := ComparedList[I].FilePath;
689     if ComparedList[I].CheckResult <> Flist_CheckFile_Identical then begin
690       //Обнаружено несоответствие. Смотрим - чего за субж. Для начала - файл это или директория.
691       if ComparedList[I].FileType = Flist_Filetype_File then begin
692         //Файл. Смотрим чего с ним надо сделать.
693         if (ComparedList[I].CheckResult = Flist_CheckFile_NonIdentical) or (ComparedList[I].CheckResult = Flist_CheckFile_ElementNotExists) then begin
694           //Файл либо изменился, либо появился там где его не было - добавляем его в инсталляху.
695           //Считаем количество элементов в строке файла.
696           ElemsNum := 3;  //Это минимум.
697           if IssF_FilesAddFlags = true then begin
698             //Добавлять флаги.
699             ElemsNum := ElemsNum+1;
700           end;
701           //Собсно выделяем память..
702           SetLength(FilesList[RealFilesListSize],ElemsNum);
703           //Пишем инфу для добавляемого файла...
704           FilesList[RealFilesListSize,0].Name := 'Source';
705           FilesList[RealFilesListSize,0].Value := RightStr(ComparedList[I].FilePath,Length(ComparedList[I].FilePath)-2);
706           FilesList[RealFilesListSize,1].Name := 'DestDir';
707           FilesList[RealFilesListSize,1].Value := AddLastSlash('{app}'+ExtractFilePath(RightStr(ComparedList[I].FilePath,Length(ComparedList[I].FilePath)-1)));
708           FilesList[RealFilesListSize,2].Name := 'Components';
709           FilesList[RealFilesListSize,2].Value := ComponentName;
710           if IssF_FilesAddFlags = true then begin
711             FilesList[RealFilesListSize,3].Name := 'Flags';
712             FilesList[RealFilesListSize,3].Value := IssF_FilesAddingFlags;
713           end;
714           //Увеличиваем счетчик количества элементов в массиве.
715           RealFilesListSize := RealFilesListSize+1;
716         end
717         else if ComparedList[I].CheckResult = Flist_CheckFile_FileNotExists then begin
718           //Файло исчезло в новой версии. Добавляем команду на удаление файла %).
719           //Добавляем в новый элемент 3 нужных значений команды:
720           SetLength(DeleteList[RealDeleteListSize],3);
721           //Ну, и собсно сама команда:
722           DeleteList[RealDeleteListSize,0].Name := 'Name';
723           DeleteList[RealDeleteListSize,0].Value := DelLastSlash('{app}'+RightStr(ComparedList[I].FilePath,Length(ComparedList[I].FilePath)-1));
724           DeleteList[RealDeleteListSize,1].Name := 'Type';
725           DeleteList[RealDeleteListSize,1].Value := 'files';
726           DeleteList[RealDeleteListSize,2].Name := 'Components';
727           DeleteList[RealDeleteListSize,2].Value := ComponentName;
728           //Увеличиваем счетчик количества элементов в массиве.
729           RealDeleteListSize := RealDeleteListSize+1;
730         end;
731       end
732       else if ComparedList[I].FileType = Flist_Filetype_Directory then begin
733         //Директория. Не ссылка ли это на себя?
734         if Length(ComparedList[I].FilePath) > 2 then begin
735           //Не, нормальная дира, можно обрабатывать дальше.
736           //Тут только 2 варианта - либо директория появилась, либо она исчезла.
737           if ComparedList[I].CheckResult = Flist_CheckFile_ElementNotExists then begin
738             //Появилась новая директория, добавим её.
739             //Считаем количество элементов в строке файла.
740             ElemsNum := 2;  //Это минимум.
741             if IssF_DirsAddFlags = true then begin
742               //Добавлять флаги.
743               ElemsNum := ElemsNum+1;
744             end;
745             //Собсно выделяем память...
746             SetLength(DirsList[RealDirsListSize],ElemsNum);
747             //Пишем инфу для добавляемой директории...
748             DirsList[RealDirsListSize,0].Name := 'Name';
749             DirsList[RealDirsListSize,0].Value := DelLastSlash('{app}'+RightStr(ComparedList[I].FilePath,Length(ComparedList[I].FilePath)-1));
750             DirsList[RealDirsListSize,1].Name := 'Components';
751             DirsList[RealDirsListSize,1].Value := ComponentName;
752             if IssF_DirsAddFlags = true then begin
753               DirsList[RealDirsListSize,2].Name := 'Flags';
754               DirsList[RealDirsListSize,2].Value := IssF_DirsAddingFlags;
755             end;
756             //Увеличиваем счетчик количества элементов в массиве.
757             RealDirsListSize := RealDirsListSize+1;
758           end
759           else if ComparedList[I].CheckResult = Flist_CheckFile_FileNotExists then begin
760             //Директория исчезла. Добавляем команду на её удаление (только для пустой диры ессно).
761             //Причем добавляем команду в отдельный список, который будет добавлен в конец списка
762             //удаления в конце работы функции чтоб директории удалялись уже после всех файлов ибо
763             //должны быть пусты.
764            
765             //Добавляем в новый элемент 3 нужных значений команды:
766             SetLength(DirDeleteList[RealDirDeleteListSize],3);
767             //Ну, и собсно сама команда:
768             DirDeleteList[RealDirDeleteListSize,0].Name := 'Name';
769             DirDeleteList[RealDirDeleteListSize,0].Value := DelLastSlash('{app}'+RightStr(ComparedList[I].FilePath,Length(ComparedList[I].FilePath)-1));
770             DirDeleteList[RealDirDeleteListSize,1].Name := 'Type';
771             DirDeleteList[RealDirDeleteListSize,1].Value := 'dirifempty';
772             DirDeleteList[RealDirDeleteListSize,2].Name := 'Components';
773             DirDeleteList[RealDirDeleteListSize,2].Value := ComponentName;
774             //Увеличиваем счетчик количества элементов в массиве.
775             RealDirDeleteListSize := RealDirDeleteListSize+1;
776           end;
777         end;
778       end;
779     end;;
780   end;
781  
782   //Инфа добавлена. Устаканиваем размеры массивов...
783   SetLength(DirsList,RealDirsListSize);
784   SetLength(FilesList,RealFilesListSize);
785   SetLength(DeleteList,RealDeleteListSize);
786   SetLength(DirDeleteList,RealDirDeleteListSize);
787  
788   //Добавляем инфу по удалению директорий в конец общей инфы по удалению...
789   Self.AddIniValueList(DirDeleteList,DeleteList);
790  
791   //И записываем измененную инфу обратно в файл...
792   Self.WriteIniValueList('Dirs',DirsList);
793   Self.WriteIniValueList('Files',FilesList);
794   Self.WriteIniValueList('InstallDelete',DeleteList);
795  
796   //Результат.
797   Result := true;
798  
799   //Очистка мусора.
800   SetLength(ComparedList,0);
801   SetLength(DirsList,0,0);
802   SetLength(FilesList,0,0);
803   SetLength(DeleteList,0,0);
804   SetLength(DirDeleteList,0,0);
805 end;
806
807 function TIssFormat.AddNewFilesFromFlists(const OldFlistFileName, NewFlistFileName, ComponentName : AnsiString) : Boolean;
808 //Добавить устанавливаемые файлы из сравнения старого и нового FList-а для указанного компонента.
809 var
810   OldFlistFile, NewFlistFile : TFlistFormat;
811 begin
812   //Инициализация...
813   Result := false;
814   OldFlistFile := TFlistFormat.Create;
815   NewFlistFile := TFlistFormat.Create;
816
817   //Если flist-файлеги есть - читаем их.
818   if (FileExists(OldFlistFileName) = true) and (FileExists(NewFlistFileName) = true) then begin
819     //Прочитать файлеги.
820     OldFlistFile.Load(OldFlistFileName);
821     NewFlistFile.Load(NewFlistFileName);
822     //Проставить корень Flist-у.
823     OldFlistFile.GlobalRoot := Self.GetSourceDir();
824     NewFlistFile.GlobalRoot := Self.GetSourceDir();
825     //Вызвать функцию реально выполняющую задачу.
826     Result := Self.AddNewFilesFromFlists(OldFlistFile,NewFlistFile,ComponentName);
827   end;
828
829   //Уборка мусора...
830   OldFlistFile.Free;
831   NewFlistFile.Free;
832 end;
833
834 function TIssFormat.AddNewFilesFromDirs(const OldDirName, NewDirName, ComponentName : AnsiString) : Boolean;
835 //Добавить устанавливаемые файлы из сравнения старой и новой диры для указанного компонента.
836 var
837   OldFlistFile, NewFlistFile : TFlistFormat;
838 begin
839   //Инициализация...
840   Result := false;
841   OldFlistFile := TFlistFormat.Create;
842   NewFlistFile := TFlistFormat.Create;
843  
844   //Настройка...
845   OldFlistFile.PathsAreAbsolute := false;
846   OldFlistFile.AddSize := true;
847   OldFlistFile.AddCRC32 := true;
848   OldFlistFile.GlobalRoot := OldDirName;
849   NewFlistFile.PathsAreAbsolute := false;
850   NewFlistFile.AddSize := true;
851   NewFlistFile.AddCRC32 := true;
852   NewFlistFile.GlobalRoot := NewDirName;
853
854   //Читаем инфу про директории в объекты flist-а.
855   if (OldFlistFile.AddRealDirectory(OldDirName,true) = true) and (NewFlistFile.AddRealDirectory(NewDirName,true) = true) then begin
856     //Если все прочитано успешно - переправить глобальный корень...
857     OldFlistFile.GlobalRoot := Self.GetSourceDir();
858     NewFlistFile.GlobalRoot := Self.GetSourceDir();
859     //... и вызвать функцию реально выполняющую задачу.
860     Result := Self.AddNewFilesFromFlists(OldFlistFile,NewFlistFile,ComponentName);
861   end;
862
863   //Уборка мусора...
864   OldFlistFile.Free;
865   NewFlistFile.Free;
866 end;
867
868 function TIssFormat.ReadCodeConstValue(const ConstName : AnsiString) : AnsiString;
869 //Прочитать значение конкретной константы.
870 begin
871   //Инициализация.
872   Result := '';
873  
874   //Подгружаем код.
875   if Self.UpdatePasModifier() = true then begin;
876     //Читаем значение константы.
877     Result := Self.PasModifier.ReadCodeConstValue(ConstName);
878   end;
879 end;
880
881 function TIssFormat.WriteCodeConstValue(const ConstName, ConstValue : AnsiString) : boolean;
882 //Записать значение конкретной константы.
883 begin
884   //Инициализация.
885   Result := true;
886  
887   //Подгружаем код.
888   if Self.UpdatePasModifier() = true then begin
889     //Есть. Меняем константу.
890     Self.PasModifier.WriteCodeConstValue(ConstName, ConstValue);
891     //И пишем код обратно.
892     Result := Self.SaveFromPasModifier();
893   end
894   else begin
895     //Обломс, не удалось подгрузить код, текст про ошибку уже записан в мессагу.
896     Result := false;
897   end;
898 end;
899
900 function TIssFormat.CodeFunctionExists(const FunctionName : AnsiString) : Boolean;
901 //Существует ли такая функция в коде?
902 begin
903   //Инициализация.
904   Result := false;
905  
906   //Подгружаем код.
907   if Self.UpdatePasModifier() = true then begin
908     //Есть. Собсно смотрим чего там с функцией.
909     Result := PasModifier.FunctionIsExists(FunctionName);
910   end;
911 end;
912
913 function TIssFormat.WriteCodeFunction(const FunctionName, FunctionContent : AnsiString) : Boolean;
914 //Записать функцию в Code, если уже есть - заменить.
915 begin
916   //Инициализация.
917   Result := true;
918  
919   //Подгружаем код.
920   if Self.UpdatePasModifier() = true then begin
921     //Есть. Пишем функцию.
922     if Self.PasModifier.WriteFunction(FunctionName, FunctionContent) = true then begin;
923       //И пишем код обратно.
924       Result := Self.SaveFromPasModifier();
925     end
926     else begin
927       //Не удалось записать функцию.
928       Result := false;
929       Self.ErrorMessage := _('TPascalCodeModifier - unknown error while trying to write a function ')+FunctionName;
930     end;
931   end
932   else begin
933     //Обломс, не удалось подгрузить код, текст про ошибку уже записан в мессагу.
934     Result := false;
935