/////////////////////////////////////////////////////////// // Copyright (C) 2007 Gipat Group // // Распространяется на условиях LGPL 2.1 // // см. файл lgpl.txt // // // // www.gipatgroup.org // /////////////////////////////////////////////////////////// //К работе над данным файлом приложили руки, ноги.... короче аффтары: // 1) Sagrer (sagrer@yandex.ru) //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////// // Модуль для работы с файлами VerInfoTxt // // В этом файле хранится инфа о версии. // // версия формата - 1 // //////////////////////////////////////////////////// unit VerInfoTxtFormat; {$IFDEF FPC} {$mode objfpc} {$ENDIF FPC} {$H+} interface uses Classes, SysUtils, TextFileInString, ExtraFunctions {$IFNDEF LCL}, StrUtils {$ENDIF LCL}; const VIT_FormatVersion = 1; //Номер версии формата в данном сырце. //Коды статуса: VIT_Status_Unknown = -1; //Статус неизвестен VIT_Status_Alpha = 0; //Альфа. VIT_Status_Beta = 1; //Бета. VIT_Status_ReleaseCandidat = 3; //Релиз-кандидат. VIT_Status_Release = 4; //Релиз. type TVerInfoTxtFormat = class //Класс для работы с файлами формата VerInfoTxt (*.vit). private //Переменные VerNum : Integer; //Номер версии загруженного формата... //Закрытые методы... procedure ParseVerNum(Buff : AnsiString); //Прочитать инфу о версии формата из Buff procedure ParseStatus(Buff : AnsiString); //Прочитать инфу о статусе из Buff public //Переменные Ver1 : Integer; //Разряд 1 номера версии... Ver2 : Integer; //Разряд 2 номера версии... Ver3 : Integer; //Разряд 3 номера версии... Ver4 : Integer; //Разряд 4 номера версии... Status : Integer; //Код статуса... RCNum : Integer; //Номер релиз-кандидата если это релиз-кандидат. ErrorMessage : AnsiString; //Сообщение о ошибке если была. //Конструкторы-деструкторы... constructor Create; destructor Destroy; override; //Открытые методы... procedure Clear(); //Очистить инфу класса и проставить дефолтные значения. function Load(const FileName : AnsiString) : boolean; //Загрузить файл в класс. function Save(const FileName : AnsiString) : boolean; //Сохранить инфу из класса в файл. function GenerateStatusString(const FullMode : boolean = false; const InFileFormat : boolean = false) : AnsiString; //Сгенерить статус в текстовом виде. function GenerateVersionString() : AnsiString; //Сгенерить строку о версии для вывода например в окошко about. function GenerateVersionString_nosvn() : AnsiString; //Сгенерить строку о версии для вывода например в окошко about. Без явного выделения ревизии. function GenerateFNVersionString_nostatus() : AnsiString; //Сгенерить короткую строку о версии для вывода в имя файла, но без статуса. function GenerateFNVersionString() : AnsiString; //Сгенерить короткую строку о версии для вывода в имя файла. function GenerateShortVersionString() : AnsiString; //Сгенерить короткую строку о версии для вывода туда где дефицит места. function GenerateShortVersionString_nosvn() : AnsiString; //Сгенерить короткую строку о версии для вывода туда где дефицит места. Без явного выделения ревизии. function GenerateDotsVersionString() : AnsiString; //Сгенерить короткую строку о версии, которая содержит исключительно цифры и точки. function ReadFromStringEx(const VerString : AnsiString; const Separator : AnsiString) : Boolean; //Попытаться пропарсить инфу в VerString и собсно забить её в инфу класса. Предполагается строка версии в формате как GenerateShortVersionString_nosvn но с произвольным разделителем номеров вместо точки. function ReadFromString(const VerString : AnsiString) : Boolean; //Попытаться пропарсить инфу в VerString и собсно забить её в инфу класса. Предполагается строка версии в формате GenerateShortVersionString_nosvn. function ReadFromFNString(const VerFNString : AnsiString) : Boolean; //Попытаться пропарсить инфу в VerString и собсно забить её в инфу класса. Предполагается строка версии в формате GenerateFNVersionString. function IsSameVersion(var AnotherVit : TVerInfoTxtFormat) : Boolean; //Сравнить версии. Если одинаковы - вернет true, иначе false. function IIsNewerThenOldVit(var OldVit : TVerInfoTxtFormat) : Boolean; //Сравнить версию с указанным vit - если в текущем классе версия новее - вернет true иначе false. end; implementation ///////////////////////////////////////////// // TVerInfoTxtFormat // ///////////////////////////////////////////// //-----------------------------------------// // Конструкторы-деструкторы... // //-----------------------------------------// constructor TVerInfoTxtFormat.Create; begin //Проставить дефолтные значения... Self.Clear(); ErrorMessage := 'none'; //Создать вложенные объекты классов... end; destructor TVerInfoTxtFormat.Destroy; begin //Выкидываем мусор //Выполнить унаследованный деструктор inherited; end; //------------------------------------------// // Закрытые методы... // //------------------------------------------// procedure TVerInfoTxtFormat.ParseVerNum(Buff : AnsiString); //Прочитать инфу о версии формата из Buff begin Parse(Buff, ' '); VerNum := StrToInt(Trim(Buff)); end; procedure TVerInfoTxtFormat.ParseStatus(Buff : AnsiString); //Прочитать инфу о статусе из Buff begin if Buff = 'a' then begin //Статус - альфа. Self.Status := VIT_Status_Alpha; end else if Buff = 'b' then begin //Статус - бета. Self.Status := VIT_Status_Beta; end else if (Buff = 'r') or (Length(Buff)=0) then begin //Статус - релиз. Self.Status := VIT_Status_Release; end else if Length(Buff) > 1 then begin //Сложное обозначение статуса. В принципе пока что это может быть только релиз-кандидат. //Статус - релиз-кандидат. Self.Status := VIT_Status_ReleaseCandidat; //Читаем номер кандидата. Self.RCNum := StrToInt(RightStr(Buff,Length(Buff)-2)); end; end; //------------------------------------------// // Открытые методы... // //------------------------------------------// procedure TVerInfoTxtFormat.Clear(); //Очистить инфу класса и проставить дефолтные значения. begin //Проставить дефолтные значения... VerNum := -1; Ver1 := -1; Ver2 := -1; Ver3 := -1; Ver4 := -1; Status := VIT_Status_Unknown; RCNum := -1; end; function TVerInfoTxtFormat.Load(const FileName : AnsiString) : boolean; //Загрузить файл в класс. var FileStr1 : TTextFileInString; AllOk : boolean; begin //Инициализация. FileStr1 := TTextFileInString.Create; Result := false; //Собсно грузим... AllOk := FileExists(FileName); if AllOk = false then begin //Если файла не существует... ErrorMessage := 'File '+FileName+' is not exists.'; end else begin //Если сам файлик вообще существует... Загружаем... AllOk := FileStr1.Load(FileName); if AllOk = false then begin //Не удалось загрузить файл. ErrorMessage := 'Error, loading file '+FileName; end; end; if AllOk = true then begin //Ок, загружено. Читаем сигнатуру... if FileStr1.CurReadLn() <> 'VerInfoTxt' then begin //Это не VerInfoTxt-файл. AllOk := false; ErrorMessage := 'File '+FileName+' is not VerInfoTxt file.'; end; end; if AllOk = true then begin //Проверяем версию формата... ParseVerNum(Trim(FileStr1.CurReadLn())); if Self.VerNum > VIT_FormatVersion then begin //Формат более новой версии чем код в бинарнике. AllOk := false; ErrorMessage := 'File '+FileName+' has more new version ('+IntToStr(Self.VerNum)+') then i know ('+IntToStr(VIT_FormatVersion)+'). Aborted loading. Try update to a new version of this software.'; end; end; if AllOk = true then begin //Собсно читаем инфу... //Когда будет версий формата больше одной - тут будет еще и поверсионка. //Ver Ver1 := StrToInt(Trim(FileStr1.CurReadLn())); Ver2 := StrToInt(Trim(FileStr1.CurReadLn())); Ver3 := StrToInt(Trim(FileStr1.CurReadLn())); Ver4 := StrToInt(Trim(FileStr1.CurReadLn())); //Status ParseStatus(Trim(FileStr1.CurReadLn())); //Ну, вроде бы все что надо прочитано. Теперь отмечаем что фсеок и собсно все. Result := true; end; //Чистим мусор. FileStr1.Free; end; function TVerInfoTxtFormat.Save(const FileName : AnsiString) : boolean; //Сохранить инфу из класса в файл. var FileStr1 : TTextFileInString; begin //Все достаточно просто. Создаем пустой файл и просто по порядку вписываем нужные строки... //Инициализация FileStr1 := TTextFileInString.Create; //Result := false; //Собсно генерим файл для сейва. FileStr1.MakNewFile; FileStr1.AddStr('VerInfoTxt'); //Сигнатура FileStr1.AddStr('v '+IntToStr(VIT_FormatVersion)); //Версия формата FileStr1.AddStr(IntToStr(Ver1)); //Разряды версии... FileStr1.AddStr(IntToStr(Ver2)); //--""-- FileStr1.AddStr(IntToStr(Ver3)); //--""-- FileStr1.AddStr(IntToStr(Ver4)); //--""-- FileStr1.AddStr(GenerateStatusString(false,true)); //Статус //И пишем сгенеренное на диск. FileStr1.Save(FileName); //Если там был какой-то файл уже - то его уже переколбасило, старый файл потерян %). //Ибо надо было проверять это все извне этой функции, там где все вызывается, это не работа //для объекта этого класса - проверять чего там есть или нет и разговаривать с юзверем, ему вообще //без понятия режим работы, толи он в консоли, толи GUI, толи еще как.... Result := true; //Чистим мусор FileStr1.Free; end; function TVerInfoTxtFormat.GenerateStatusString(const FullMode : boolean = false; const InFileFormat : boolean = false) : AnsiString; //Сгенерить статус в текстовом виде. begin //Дефолтное значение. Result := ''; //Проверяем статус и в зависимости от вариантов генерим значение. if Status = VIT_Status_Alpha then begin //Альфа. if FullMode = false then begin //Коротко Result := 'a'; end else begin //Длинно Result := ' Alpha'; end; end else if Status = VIT_Status_Beta then begin //Бета. if FullMode = false then begin //Коротко Result := 'b'; end else begin //Длинно Result := ' Beta'; end; end else if Status = VIT_Status_Release then begin //Релиз - не пишем ничего. Result := ''; end else if Status = VIT_Status_ReleaseCandidat then begin //Релиз-кандидат. В коротком режиме - для юзверя надо писать большое RC а для файла - маленькое. if FullMode = false then begin //Коротко if InFileFormat = true then begin //Маленький вариант - по стандарту для записи в файл VerInfoTxt. Result := 'rc'+IntToStr(RCNum); end else begin //Большой вариант - более стандартно для вывода юзверю. Result := ' RC'+IntToStr(RCNum); end; end else begin //Длинно Result := ' Release Candidat N '+IntToStr(RCNum); end; end else if Status = VIT_Status_Unknown then begin //Статус неизвестен. В норме его не бывает, но мало ли... //Юзверю не выведем ничего, в файл скорее всего сохранится пустая строка. //Причем при чтении такой строки в принципе скорее всего в классе опять же будет //распознан статус как VIT_Status_Unknown. //Вообще это все может быть только в случае какого-то глюка, тут сложно что-то предвидеть. Result := ''; end; end; function TVerInfoTxtFormat.GenerateVersionString() : AnsiString; //Сгенерить строку о версии для вывода например в окошко about. begin //Добавляем начальные цифры версии... Result := IntToStr(Ver1)+'.'+IntToStr(Ver2)+'.'+IntToStr(Ver3); //Теперь статус... Result := Result+GenerateStatusString(true); //Теперь ревизия. Result := Result+', revision: '+IntToStr(Ver4)+'.'; end; function TVerInfoTxtFormat.GenerateVersionString_nosvn() : AnsiString; //Сгенерить строку о версии для вывода например в окошко about. Без явного выделения ревизии. begin //Добавляем начальные цифры версии... Result := IntToStr(Ver1)+'.'+IntToStr(Ver2)+'.'+IntToStr(Ver3)+'.'+IntToStr(Ver4); //Теперь статус... Result := Result+GenerateStatusString(true)+'.'; end; function TVerInfoTxtFormat.GenerateFNVersionString_nostatus() : AnsiString; //Сгенерить короткую строку о версии для вывода в имя файла, но без статуса. begin //Добавляем начальные цифры версии... Result := IntToStr(Ver1)+'_'+IntToStr(Ver2)+'_'+IntToStr(Ver3)+'_'+IntToStr(Ver4); end; function TVerInfoTxtFormat.GenerateFNVersionString() : AnsiString; //Сгенерить короткую строку о версии для вывода в имя файла. begin //Добавляем начальные цифры версии... Result := Self.GenerateFNVersionString_nostatus(); //Теперь статус... Result := Result+GenerateStatusString(false,true); end; function TVerInfoTxtFormat.GenerateShortVersionString() : AnsiString; //Сгенерить короткую строку о версии для вывода туда где дефицит места. begin //Добавляем начальные цифры версии... Result := IntToStr(Ver1)+'.'+IntToStr(Ver2)+'.'+IntToStr(Ver3); //Теперь статус... Result := Result+GenerateStatusString(false,true); //Теперь ревизия. Result := Result+', r'+IntToStr(Ver4)+'.'; end; function TVerInfoTxtFormat.GenerateShortVersionString_nosvn() : AnsiString; //Сгенерить короткую строку о версии для вывода туда где дефицит места. Без явного выделения ревизии. begin //Добавляем начальные цифры версии... Result := IntToStr(Ver1)+'.'+IntToStr(Ver2)+'.'+IntToStr(Ver3)+'.'+IntToStr(Ver4); //Теперь статус... Result := Result+GenerateStatusString(false,true)+'.'; end; function TVerInfoTxtFormat.GenerateDotsVersionString() : AnsiString; //Сгенерить короткую строку о версии, которая содержит исключительно цифры и точки. begin //Добавляем начальные цифры версии... Result := IntToStr(Ver1)+'.'+IntToStr(Ver2)+'.'+IntToStr(Ver3)+'.'+IntToStr(Ver4); end; function TVerInfoTxtFormat.ReadFromStringEx(const VerString : AnsiString; const Separator : AnsiString) : Boolean; //Попытаться пропарсить инфу в VerString и собсно забить её в инфу класса. //Предполагается строка версии в формате как GenerateShortVersionString_nosvn //но с произвольным разделителем номеров вместо точки. var TempVerStr, TempParsedStr : AnsiString; begin //Инициализация. Result := true; Self.Clear(); //Собсно, парсим. TempVerStr := VerString; //1 if Length (TempVerStr) > 0 then begin TempParsedStr := Parse(TempVerStr,Separator); end else Result := false; //т.е. несоответствие формату. if (IsNumericStr(TempParsedStr) = true) and (Result = true) then begin Self.Ver1 := StrToInt(TempParsedStr); end else Result := false; //2 if (Length (TempVerStr) > 0) and (Result = true) then begin TempParsedStr := Parse(TempVerStr,Separator); end else Result := false; if (IsNumericStr(TempParsedStr) = true) and (Result = true) then begin Self.Ver2 := StrToInt(TempParsedStr); end else Result := false; //3 if (Length (TempVerStr) > 0) and (Result = true) then begin TempParsedStr := Parse(TempVerStr,Separator); end else Result := false; if (IsNumericStr(TempParsedStr) = true) and (Result = true) then begin Self.Ver3 := StrToInt(TempParsedStr); end else Result := false; //4 if (Length (TempVerStr) > 0) and (Result = true) then begin //А вот тут надо отпарсить "номерную" часть строки. TempParsedStr := ParseNumericHead(TempVerStr); end else Result := false; if (IsNumericStr(TempParsedStr) = true) and (Result = true) then begin Self.Ver4 := StrToInt(TempParsedStr); end else Result := false; //Статус. if Result = true then begin //Просто парсяем статус. Self.ParseStatus(TempVerStr); //И теоретически если там за статусом ничего нема - то делаем строку пустой. Если там че-то есть - то она останется не пустой и это даст ошибку. Parse(TempVerStr,Separator); end; if (Length (TempVerStr) > 0) and (Result = true) then begin //А должно было быть пусто. Ошибк. Result := false; end; if Result = false then begin Self.ErrorMessage := 'VIT: incorrect version format.'; end; end; function TVerInfoTxtFormat.ReadFromString(const VerString : AnsiString) : Boolean; //Попытаться пропарсить инфу в VerString и собсно забить её в инфу класса. //Предполагается строка версии в формате GenerateShortVersionString_nosvn. begin Result := Self.ReadFromStringEx(VerString,'.'); end; function TVerInfoTxtFormat.ReadFromFNString(const VerFNString : AnsiString) : Boolean; //Попытаться пропарсить инфу в VerString и собсно забить её в инфу класса. //Предполагается строка версии в формате GenerateFNVersionString. begin Result := Self.ReadFromStringEx(VerFNString,'_'); end; function TVerInfoTxtFormat.IsSameVersion(var AnotherVit : TVerInfoTxtFormat) : Boolean; //Сравнить версии. Если одинаковы - вернет true, иначе false. begin //Инициализация. Result := false; if (Self.Ver1 = AnotherVit.Ver1) and (Self.Ver2 = AnotherVit.Ver2) and (Self.Ver3 = AnotherVit.Ver3) and (Self.Ver4 = AnotherVit.Ver4) and (Self.Status = AnotherVit.Status) then begin //Ага, почти идентичны. if (Self.Status = VIT_Status_ReleaseCandidat) and (AnotherVit.Status = VIT_Status_ReleaseCandidat) then begin //Надо сверить номера релиз-кандидатов. if Self.RCNum = AnotherVit.RCNum then begin //Действительно идентичны. Result := true; end; end else begin //Точно идентичны. Result := true; end; end; end; function TVerInfoTxtFormat.IIsNewerThenOldVit(var OldVit : TVerInfoTxtFormat) : Boolean; //Сравнить версию с указанным vit - если в текущем классе версия новее - вернет true иначе false. begin //Инициализация. Result := true; //Сравниваем. if Self.Ver1 < OldVit.Ver1 then begin Result := false; end; if Result = true then begin if Self.Ver2 < OldVit.Ver2 then begin Result := false; end; end; if Result = true then begin if Self.Ver3 < OldVit.Ver3 then begin Result := false; end; end; if Result = true then begin if Self.Ver4 < OldVit.Ver4 then begin Result := false; end; end; if (Result = true) and (Self.Ver1 = OldVit.Ver1) and (Self.Ver2 = OldVit.Ver2) and (Self.Ver3 = OldVit.Ver3) and (Self.Ver4 = OldVit.Ver4) then begin if Self.Status < OldVit.Status then begin Result := false; end else begin //Особо сравнить релиз-кандидаты. if (Self.Status = VIT_Status_ReleaseCandidat) and (OldVit.Status = VIT_Status_ReleaseCandidat) then begin //Сравниваем нумер кандидата. if Self.RCNum < OldVit.RCNum then begin Result := false; end; end; end; end; if Result = true then begin //Проверить - не идентичны ли случаем версии? if Self.IsSameVersion(OldVit) = true then begin //Идентичны - значит текущая версия не новее. Result := false; end; end; end; end.